我尝试了懒惰的I / O,但整个文件都被消耗了

时间:2014-03-30 07:36:48

标签: haskell lazy-evaluation

我是Haskell的新手。我想只将文本文件的 N 字符读入内存。所以我写了这段代码:

main :: IO()
main = do
  inh <- openFile "input.txt" ReadMode
  transformedList <- Control.Monad.liftM (take 4) $ transformFileToList inh
  putStrLn "transformedList became available"
  putStrLn transformedList
  hClose inh

transformFileToList :: Handle -> IO [Char]
transformFileToList h = transformFileToListAcc h []

transformFileToListAcc :: Handle -> [Char] -> IO [Char]
transformFileToListAcc h acc = do
  readResult <- tryIOError (hGetChar h)
  case readResult of
    Left e -> if isEOFError e then return acc else ioError e
    Right c -> do let acc' = acc ++ [transformChar c]
                  putStrLn "got char"
                  unsafeInterleaveIO $ transformFileToListAcc h acc'

我的输入文件有几行,第一行是&#34; hello world&#34;,当我运行这个程序时,我得到了这个输出:

got char
transformedList became available
got char
["got char" a bunch of times]
hell

我的期望是&#34;得到了char&#34;只发生了4次。而是读取整个文件,一次读取一个字符,然后只读取前4个字符。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

我承认我不明白unsafeInterLeaveIO是如何运作的,但我怀疑这里的问题与它有某种关系。也许在这个例子中你试图理解unsafeInterLeaveIO,但如果我是你,我会尽量避免直接使用它。以下是我在您的具体情况下如何做到这一点。

main :: IO ()
main = do
    inh <- openFile "input.txt" ReadMode
    charList <- replicateM 4 $ hGetChar inh
    let transformedList = map transformChar charList
    putStrLn "transformedList became available"
    putStrLn transformedList
    hClose inh

这应该只读取文件的前4个字符。

如果您正在寻找真正有效的流媒体解决方案,我会调查pipesconduit而不是unsafeInterLeaveIO