0

我是 Haskell 初学者,仍在学习 monad 转换器。

我正在尝试使用流字节串库来读取二进制文件,处理字节块,并在处理每个块时打印结果。我相信这是一个流行的streaming库,它提供了惰性字节串的替代方案。看来作者复制粘贴了惰性字节字符串文档并添加了一些任意示例。

这些例子runResourceT没有讨论它是什么或如何使用它。似乎应该runResourceT在执行操作的任何流式字节字符串函数上使用。这很好,但是如果我正在读取一个处理块并打印它们的无限流呢?每次我想处理块时都应该调用 runResourceT 吗?

我的代码是这样的:

import qualified Data.ByteString.Streaming as BSS
import System.TimeIt

main = timeIt $ processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"

而且我不确定如何组织processByteChunks为遍历二进制文件的递归函数。

如果我runResourceT只调用一次,它会在打印之前读取无限文件,对吗?这似乎很糟糕。

main = timeIt $ runResourceT $ processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"
4

1 回答 1

3

ResourceT你完成资源时,monad 会及时清理资源。在这种情况下,它将确保在BSS.readFile消费流时关闭打开的文件句柄。(除非流真的是无限的,在这种情况下我猜它不会。)

在您的应用程序中,您只想调用它一次,因为您不希望在读取所有块之前关闭文件。别担心——它与输出的时间或类似的事情无关。

processByteChunks这是一个应该工作的递归示例。它将延迟读取并在延迟读取块时生成输出:

import Control.Monad.IO.Class
import Control.Monad.Trans.Resource
import qualified Data.ByteString.Streaming as BSS
import qualified Data.ByteString as BS
import System.TimeIt

main :: IO ()
main = timeIt $ runResourceT $
  processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"

processByteChunks :: MonadIO m => BSS.ByteString m () -> m ()
processByteChunks = go 0 0
  where go len nulls stream = do
          m <- BSS.unconsChunk stream
          case m of
            Just (bs, stream') -> do
              let len' = len + BS.length bs
                  nulls' = nulls + BS.length (BS.filter (==0) bs)
              liftIO $ print $ "cumulative length=" ++ show len'
                                      ++ ", nulls=" ++ show nulls'
              go len' nulls' stream'
            Nothing -> return ()
于 2019-05-12T03:01:49.870 回答