hGetContents と hClose
hGetContents に渡したハンドラを hClose すると、hGetContents の結果が空文字列になる。
import IO (openFile, IOMode(ReadMode), hGetContents, hClose, bracket) f1 = do h <- openFile "hoge.txt" ReadMode s <- hGetContents h return s f2 = bracket (openFile "hoge.txt" ReadMode) (hClose) (hGetContents) main = do run "f1" f1 run "f2" f2 where run name act = do putStrLn name putStrLn =<< act putStrLn ""
f1 では hoge.txt の内容が得られて、f2 では空文字列が得られる。
で紹介されているように、hGetContents の結果文字列が評価されるまで hGetContents の IO 処理は遅延されるわけだから、その前に hClose すると空になっちゃうよという話。
じゃあこれは?
import IO (openFile, IOMode(ReadMode), hGetContents, hClose, bracket) import Control.Exception (evaluate) f3 = bracket (openFile "hoge.txt" ReadMode) (hClose) (\h -> hGetContents h >>= evaluate) f4 = bracket (openFile "hoge.txt" ReadMode) (hClose) (\h -> hGetContents h >>= return . length) f5 = bracket (openFile "hoge.txt" ReadMode) (hClose) (\h -> hGetContents h >>= print . length)
f3 と f5 は期待した値が得られた。f4 は f2 と同じ話で、評価する前に閉じるからアウト。
evaluate は値を正格評価しつつ IO モナドでくるむ。seq と return をあわせた感じ (実装を見てみたらもっと複雑なことしてた)。