Haskell 如何通过流式ByteString跟踪进度?
我正在使用流式UTIL来流式传输HTTP响应体。我希望跟踪进度,类似于使用lazyHaskell 如何通过流式ByteString跟踪进度?,haskell,pipe,pipeline,bytestring,haskell-streaming,Haskell,Pipe,Pipeline,Bytestring,Haskell Streaming,我正在使用流式UTIL来流式传输HTTP响应体。我希望跟踪进度,类似于使用lazyByteStrings的方式。我怀疑这样做是必要的,然后减少一些累积字节的读取并返回原始流。但我无法理解,而且文档也毫无用处,大多都是与其他库的宏大比较 下面是一些我迄今为止尽最大努力编写的代码。它还没有包括计数,只是在数据流经过时尝试打印数据块的大小(并且不编译) download::ByteString->FilePath->IO() 下载i file=do req我们想要的是以两种方式遍历流(ByteStri
ByteString
s的方式。我怀疑这样做是必要的,然后减少一些累积字节的读取并返回原始流。但我无法理解,而且文档也毫无用处,大多都是与其他库的宏大比较
下面是一些我迄今为止尽最大努力编写的代码。它还没有包括计数,只是在数据流经过时尝试打印数据块的大小(并且不编译)
download::ByteString->FilePath->IO()
下载i file=do
req我们想要的是以两种方式遍历流(ByteString的)IO()
:
- 将
ByteString
s的传入长度累加起来并将更新打印到控制台的一种
- 将流写入文件的人
我们可以在函数的帮助下完成此操作,该函数具有以下类型:
copy
获取一个流并将其复制到两个不同的一元层,其中原始流的每个元素由新分离流的两个层发射
(请注意,我们正在更改基本单子,而不是函子。将函子更改为另一个流
所做的是在一个流中更改,我们对此不感兴趣。)
下面的函数获取一个流,复制它,用它累积传入字符串的长度,并返回另一个仍然可以使用的流,例如将其写入文件:
{-# LANGUAGE OverloadedStrings #-}
import Streaming
import qualified Streaming.Prelude as S
import qualified Data.ByteString as B
track :: Stream (Of B.ByteString) IO r -> Stream (Of B.ByteString) IO r
track stream =
S.mapM_ (liftIO . print) -- brings us back to the base monad, here another stream
. S.scan (\s b -> s + B.length b) (0::Int) id
$ S.copy stream
这将打印ByteString
s以及累计长度:
main :: IO ()
main = S.mapM_ B.putStr . track $ S.each ["aa","bb","c"]
这有点令人兴奋。最初由S.copy返回的外部流将驱动内部流?@MattJoiner更像是元素在lockstep中发出。事实上,你可以使用提升
来处理内部流
首先:@MattJoiner,不管它值多少,复制
是扩展的一个特例::(单子m,函子f)=>(对于所有ab.(ga->b)->fa->hb)->流fmr->流g(流hm)r
。也许这会对你的直觉有所帮助。当然,它的实现更受其类型的限制。@danidiaz有可能使它成为非阻塞的吗?我想反复调用track
,并以60FPS的速度在屏幕上显示下载进度(使用(a->IO a)->IO()
功能)。
{-# LANGUAGE OverloadedStrings #-}
import Streaming
import qualified Streaming.Prelude as S
import qualified Data.ByteString as B
track :: Stream (Of B.ByteString) IO r -> Stream (Of B.ByteString) IO r
track stream =
S.mapM_ (liftIO . print) -- brings us back to the base monad, here another stream
. S.scan (\s b -> s + B.length b) (0::Int) id
$ S.copy stream
main :: IO ()
main = S.mapM_ B.putStr . track $ S.each ["aa","bb","c"]