我如何在Haskell中实现`cat`? [英] How do I implement `cat` in Haskell?
问题描述
我试图在Haskell中编写一个简单的 cat
程序。我想将多个文件名作为参数,然后将每个文件顺序写入 STDOUT ,但我的程序只打印一个文件并退出。
我需要做什么来让我的代码打印每个文件,而不仅仅是第一个文件?
import Control.Monad作为Monad
导入System.Exit
导入System.IO作为IO
导入System.Environment作为Env
main :: IO()
main =做
- 获得命令行参数
args< - Env.getArgs
- 如果我们有参数,将它们读为文件并输出它们
if (长度ARGS大于0),那么catFileArray ARGS
- 否则,输出标准输入到stdout
,否则catHandle标准输入
catFileArray :: [文件路径] - GT; IO()
catFileArray files = do
putStrLn $==>文件数量:++(show $ length files)
- 为传入的每个文件运行`catFile`
Monad.forM_文件catFile
catFile :: FilePath - > IO()
catFile F =做
putStrLn( ==> 中++ F)
手柄< - 中openFile˚FReadMode
catHandle手柄
catHandle :: Handle - > IO()
catHandle H = Monad.forever $待办事项
EOF< - IO.hIsEOF H
如果EOF然后做
H关闭ħ
exitWith ExitSuccess
,否则
hGetLine h取代;> = putStrLn
我运行这样的代码:
runghc cat.hs file1 file2
你的问题是 exitWith
会终止整个程序。所以,你不能真的使用 forever
来遍历文件,因为显然你不想运行forever函数,直到文件结束。您可以像这样重写 catHandle
catHandle :: Handle - > IO()
catHandle H =做
EOF< - IO.hIsEOF H
如果EOF然后做
H关闭H
,否则
hGetLine h取代; > = putStrLn
catHandle h
Ie如果我们还没有达到EOF,我们会递归并读取另一行。
然而,这种方法过于复杂。您可以简单地将cat写为 main = do
文件< - getArgs
forM_文件$ \\ \\文件名 - >做
内容< - readFile文件名
putStr内容
由于懒惰我/ o,整个文件内容并没有真正加载到内存中,而是流入标准输出。
如果您对 Control中的运算符感到满意。 Monad
,整个程序可以缩短为
main = getArgs>> = mapM_ (readFile> => putStr)
I am trying to write a simple cat
program in Haskell. I would like to take multiple filenames as arguments, and write each file sequentially to STDOUT, but my program only prints one file and exits.
What do I need to do to make my code print every file, not just the first one passed in?
import Control.Monad as Monad
import System.Exit
import System.IO as IO
import System.Environment as Env
main :: IO ()
main = do
-- Get the command line arguments
args <- Env.getArgs
-- If we have arguments, read them as files and output them
if (length args > 0) then catFileArray args
-- Otherwise, output stdin to stdout
else catHandle stdin
catFileArray :: [FilePath] -> IO ()
catFileArray files = do
putStrLn $ "==> Number of files: " ++ (show $ length files)
-- run `catFile` for each file passed in
Monad.forM_ files catFile
catFile :: FilePath -> IO ()
catFile f = do
putStrLn ("==> " ++ f)
handle <- openFile f ReadMode
catHandle handle
catHandle :: Handle -> IO ()
catHandle h = Monad.forever $ do
eof <- IO.hIsEOF h
if eof then do
hClose h
exitWith ExitSuccess
else
hGetLine h >>= putStrLn
I am running the code like this:
runghc cat.hs file1 file2
Your problem is that exitWith
terminates the whole program. So, you cannot really use forever
to loop through the file, because obviously you don't want to run the function "forever", just until the end of the file. You can rewrite catHandle
like this
catHandle :: Handle -> IO ()
catHandle h = do
eof <- IO.hIsEOF h
if eof then do
hClose h
else
hGetLine h >>= putStrLn
catHandle h
I.e. if we haven't reached EOF, we recurse and read another line.
However, this whole approach is overly complicated. You can write cat simply as
main = do
files <- getArgs
forM_ files $ \filename -> do
contents <- readFile filename
putStr contents
Because of lazy i/o, the whole file contents are not actually loaded into memory, but streamed into stdout.
If you are comfortable with the operators from Control.Monad
, the whole program can be shortened down to
main = getArgs >>= mapM_ (readFile >=> putStr)
这篇关于我如何在Haskell中实现`cat`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!