【问题标题】:Haskell: why does this code fail?Haskell:为什么这段代码会失败?
【发布时间】:2012-08-17 20:42:53
【问题描述】:

当我尝试运行此代码时...

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”的第一行。你能解释一下为什么吗?最终,我试图弄清楚如何从文件输入中创建一个惰性文本列表。

【问题讨论】:

标签: haskell file-io monads lazy-evaluation


【解决方案1】:

正如 Daniel Lyons 在评论中提到的,这是由于 IO 和惰性交互造成的。

想象一下,如果你愿意的话:

  • withFile 打开文件,到文件句柄f
  • 返回使用 f 内容的 Thunk。
  • withFile 关闭文件。
  • 已评估 Thunk。已关闭的文件中没有内容。

HaskellWiki / Maintaining laziness 页面上提到了这个陷阱。

要解决此问题,您可以读取withFile 中的整个文件内容(可能通过seq 强制它)或懒惰地关闭文件而不是使用withFile

【讨论】:

    【解决方案2】:

    我想是这样的:withFile在执行完函数后关闭文件。 hGetContents 延迟读取内容(延迟 IO),到需要读取内容时,文件已关闭。

    不要使用withFile,而是尝试使用openFile,而不是关闭它。 hGetContents 将在读取文件后将文件置于半关闭状态。或者更好,直接使用readFile阅读内容

    【讨论】:

      猜你喜欢
      • 2013-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      相关资源
      最近更新 更多