haskell-jp / beginners #22 at 2022-10-16 20:12:57 +0900

Practical Haskell という本を読んでいます。分からない点があるので質問させてください。

module Main (main) where

import GHC.IO.IOMode (IOMode(ReadMode))
import GHC.IO.Handle (hGetContents, hClose)
import  (openFile)

main :: IO ()
main = do
    h <- openFile "./some.txt" ReadMode
    s <- hGetContents h
    hClose h
    print s

これを実行するとエラーになります。`./some.txt: hGetContents: illegal operation (delayed read on closed handle)`

エラーになる理屈は理解していて、`hClose h`と`print s`を入れ替えれば動作します。
他の解決策として seq または deepseq を使っても解決できると書いてあるのですが、具体的に使い方は書いてありませんでした。

hClose h する前に文字列全体を読み込めばいいので、`let !size = length s` を追加して、文字列全体を読み込むように処理を強制しました。これは動作しました。
{-# LANGUAGE BangPatterns #-}
module Main (main) where

import GHC.IO.IOMode (IOMode(ReadMode))
import GHC.IO.Handle (hGetContents, hClose)
import  (openFile)

main :: IO ()
main = do
    h <- openFile "./some.txt" ReadMode
    s <- hGetContents h
    let !size = length s
    hClose h
    print s

let !size = length s を追加したのと同じ理屈で let ds = s deepseq` s` を追加したのですが、これだとエラーになります。

{-# LANGUAGE BangPatterns #-}
module Main (main) where

import GHC.IO.IOMode (IOMode(ReadMode))
import GHC.IO.Handle (hGetContents, hClose)
import  (openFile)
import Control.DeepSeq

main :: IO ()
main = do
    h <- openFile "./some.txt" ReadMode
    s <- hGetContents h
    let ds =  s `deepseq` s
    hClose h
    print ds

let ds = s deepseq` s` ではエラーになる理由をご教示いただけないでしょうか。よろしくお願い致します。
    let ds =  s `deepseq` s
    hClose h
    print ds

の部分は ds の評価が遅延されるので
    hClose h
    print (s `deepseq` s)

と同じになるはずです
(試せてないですが)
   s `deepseq` hClose h
   print s

だと期待する動作だと思います
の部分は ds の評価が遅延されるので
そうでした。そもそも`ds` が評価されるタイミングにならないと s deepseq` s` も評価されないのでした。

  s `deepseq` hClose h
>    print s
↑で動作しました。ありがとうございます。