我如何在Haskell中实现`cat`? [英] How do I implement `cat` in Haskell?

查看:88
本文介绍了我如何在Haskell中实现`cat`?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆