我是Haskell初学者,仍在学习Monad Transformers。
我正在尝试使用流式bytestring库来读取二进制文件,处理字节块,并在处理每个块时打印结果。我相信这是一个流行的streaming
库,可替代懒惰的字节。作者看来复制了懒惰的Bytestring文档,并添加了一些任意示例。
示例提及 runResourceT
,而无需讨论它是什么或如何使用它。看来应在执行动作的任何流式bytestring函数上使用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"
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 ()