学習の素材は、
すごいHaskellたのしく学ぼう!
この表記は、私見・感想です。
期待するファイル読み込みができない
文字列を読み込むためだけのIOアクションを引数にとった withFile
を使ってはいけない。その後にputStrLn
, writeFile
などで取得した文字列を参照しようとしても、空文字になってしまう。
例えばこのようなケース。
$ cat baabaa.txt
Baa, baa, black sheep,
Have you any wool?
Yes, sir, yes, sir
Three bags full;
$
import System.IO
main = do
str <- readFile'' "baabaa.txt"
writeFile "output.txt" str -- (*1)読み込んだ文字列をファイルに書き出す
readFile'' :: FilePath -> IO String
readFile'' name = withFile name ReadMode hGetContents
このプログラムを起動すると output.txt
には何の文字列も入っておらず、これは期待通りではない。
$ cat output.txt
$
これは、次の要因で起こってしまう。
-
withFile
は、関数の終了とともにファイルハンドルを閉じてしまう - 遅延IOなので、必要になるまで( putStrLnなどが呼び出されるまで )
withFile
の結果は評価されない
このため、必要になった時にはハンドルが閉じていて期待していた文字列を評価できず、IOアクションの結果が""
となってしまう。
なお次のプログラムでも、同じように文字列を取得できなかった。
import System.IO
main = do
handle <- openFile "baabaa.txt" ReadMode
contents <- hGetContents handle
hClose handle
putStrLn contents
ハンドルが閉じている状態で
contents
に関数を適用しても、エラーとはならないようだ。また、途中でlet a = contents
などと変数にバインドしても、浅いコピーしかされていない様子だった。
参考サイト
http://stackoverflow.com/questions/9406463/withfile-vs-openfile
http://hackage.haskell.org/packages/archive/base/latest/doc/html/System-IO.html#v:withFile