UNIXっぽいストリームっぽいコマンドが作りたい。
といった時に、入力を「最後まで」読むにはどうしたらいいのという話。
何も考えずにcatっぽいのを書くとこうなる。catじゃなくてechoだな。
import System.IO main :: IO () main = do l <- getLine putStrLn l main
テストデータを用意する。
% cat test.dat Hello1 Hello2 Hello4
食わせる。
% cat test.dat | ./echo Hello1 Hello2 Hello4 echo: <stdin>: hGetLine: end of file
EOLに達した時にgetLineが例外を吐いて、誰も処理してないからエラーメッセージが出る。
getLineのマニュアルを読むと、"hGetLine stdin"と同じものですよと書いてあって、hGetLineはEOFErrorを吐くのでisEOFErrorで判別してねとご丁寧に書いてあるが、そもそも例外処理ってどう書くのとかは書いてないんだねぇ。探せばあるけど。
catchIOErrorで処理するらしいですけど、なぜか関数が見つからなかったので、deprecatedだけどcatchを使った。型は同じだしいいよね。
catchIOError, catch :: System.IO.Error
import System.IO import System.IO.Error main :: IO () main = catch loop (\e -> if isEOFError e then return () else ioError e) loop :: IO () loop = do l <- getLine putStrLn l loop
EOFErrorだったときは見なかったことにして終了、それ以外の例外だったらさらに上位に投げ返すだけです。で、mainより上に届くとエラーメッセージが出るらしい。
% cat test.dat | ./echo Hello1 Hello2 Hello4
いいのかこれで。なんかもうちょっと、EOF判定がいい感じにできる方法あるんじゃないかな。