3

このコードを実行しようとすると...

module Main where

import qualified Data.Text.Lazy.IO as LTIO
import qualified Data.Text.Lazy as LT
import System.IO (IOMode(..), withFile)

getFirstLine :: FilePath -> IO String
getFirstLine path =
        withFile path ReadMode (\f -> do
                contents <- LTIO.hGetContents f
                return ("-- "++(LT.unpack . head $ LT.lines contents)++" --"))

main::IO()
main = do
        firstLine <- getFirstLine "/tmp/foo.csv"
        print firstLine

私は得る

"-- *** Exception: Prelude.head: empty list

...「/tmp/foo.csv」の最初の行を出力すると予想される場所。その理由を教えてください。最終的に、私はファイル入力からテキストの怠惰なリストを作成する方法を理解しようとしています。

4

2 に答える 2

4

Daniel Lyons がコメントで言及しているように、これは IO と遅延の相互作用によるものです。

想像してみてください:

  • withFileは、ファイル ハンドルにファイルを開きますf
  • の内容を使用したサンクfが返されます。
  • withFileファイルを閉じます。
  • サンクが評価されます。閉じたファイルには内容がありません。

このトラップは、HaskellWiki / 怠惰の維持ページで言及されています。

withFile修正するには、ファイルの内容全体を(おそらく で強制的にseq)読み取るか、withFile.

于 2012-08-17T20:56:26.760 に答える
1

withFile関数の実行後にファイルを閉じます。hGetContentsコンテンツを遅延して読み取り(遅延IO)、読み取りが必要になるまでに、ファイルは閉じられます。

を使用する代わりに、閉じずにそのままwithFile使用してみてください。ファイルから読み取った後、ファイルをセミクローズド状態にします。または、内容を直接読んでくださいopenFilehGetContentsreadFile

于 2012-08-17T20:56:14.930 に答える