catコマンドを実装してみる

Haskellの練習として、catコマンドを実装してみる。

getConentsを使う

もっとも簡潔な実装。

-- cat1.hs
main = getContents >>= putStr

do記法を使って書くと次のようになる。

main = do
    x <- getContents
    putStr x

上のコードは下と同値である。

main = getContents >>= (\x -> putStr x)

ここで、>>=はいわゆるbind演算である。 (\x -> putStr x)putStrそのものなので、より簡潔な形に直すことで最初のコードになる。

実行結果。

$ runghc cat1.hs
hoge
hoge
fuga
fuga
[Ctrl+D]

getLineを使う

getLineで1行ずつ読む場合は、EOFErrorのハンドルが必要になる。

-- cat2.hs
import System.IO.Error

main = catchIOError catLoop handleError
    where catLoop = getLine >>= putStrLn >> catLoop
          handleError e
            | isEOFError e = return ()
            | otherwise    = ioError e

putStrLnの戻り値(IO型)はcatLoopに必要ないので、>>=の代わりに戻り値を捨てる>>を使う。 handleErrorはEOFErrorのときのみ()(unit、空の値を表す)を値に持つモナドを返し、それ以外のときはIOErrorを値に持つモナドを作って返す。

実行結果。

$ runghc cat2.hs
hoge
hoge
fuga
fuga
[Ctrl+D]

関連リンク