我正在尝试写一个简单的cat
Haskell 中的程序。我想将多个文件名作为参数,并将每个文件依次写入STDOUT,但我的程序只打印一个文件并退出。
我需要做什么才能让我的代码打印每个文件,而不仅仅是传入的第一个文件?
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
我正在运行这样的代码:
runghc cat.hs file1 file2
你的问题是exitWith
终止整个程序。所以,你不能真正使用forever
循环遍历文件,因为显然您不想“永远”运行该函数,直到文件末尾。你可以重写catHandle
像这样
catHandle :: Handle -> IO ()
catHandle h = do
eof <- IO.hIsEOF h
if eof then do
hClose h
else
hGetLine h >>= putStrLn
catHandle h
IE。如果还没有到达 EOF,我们就会递归并读取另一行。
然而,整个方法过于复杂。你可以简单地将 cat 写为
main = do
files <- getArgs
forM_ files $ \filename -> do
contents <- readFile filename
putStr contents
由于惰性 I/O,整个文件内容实际上并未加载到内存中,而是流式传输到 stdout 中。
如果您对以下运营商感到满意Control.Monad
,整个程序可以缩短为
main = getArgs >>= mapM_ (readFile >=> putStr)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)