Haskell如何在复制后将1个流分离为2个流



在haskell流中,有一个复制的例子

>>> (S.toList . mapped S.toList . chunksOf 5) $  (S.toList . mapped S.toList . chunksOf 3) $ S.copy $ each [1..10]
[[1,2,3,4,5],[6,7,8,9,10]] :> ([[1,2,3],[4,5,6],[7,8,9],[10]] :> ())

是否可以将其分为两个"干净"流,以便打印以下结果?

>>>S.print stream1
[[1,2,3,4,5],[6,7,8,9,10]]
>>>S.print stream2
[[1,2,3],[4,5,6],[7,8,9],[10]]

请注意,以上结果中没有更多的":>"。更普遍地说,我不确定是否有函数可以"简化"Stream (Of a) m rm(Of a)部分的嵌套流(或流的流(

f1::Stream (Of a) (Stream (Of b) m) r -> Stream (Of b) m r
f2::Stream (Of a) (Stream (Of b) m) r -> Stream (Of a) m r
f3::Stream (Stream (Of a) m) r -> Stream (Of a) m r

[更新]

这个问题的背景是,我正在寻找多次重用底层流的惯用方法。流是从数据库中提取的,IO可能很昂贵。我还想获得对中间流的引用,以便更好地构建代码。一些模拟代码:

my-stream-fn = do
original_stream <- pull_from_database 
let  (o1, s1) = calc_moving_average $ S.copy original_stream
(o2, s2) = calc_max $ S.copy o1
(o3, s3) = calc_min $ S.copy o2
S.print $ S.zipWith3 (x y z-> (x, y, z)) s1 s2 s3

我希望o1o2和o3与original_stream完全相同,并且在提取original_stream时只执行一次pull_from_database IO操作。

f1 = S.effects @(Stream (Of _) _) 
:: Monad m 
=> Stream (Of a) (Stream (Of b) m) r 
-> Stream (Of b) r
f2 = hoist @(Stream (Of _)) S.effects
:: Monad m
=> Stream (Of a) (Stream (Of b) m) r
-> Stream (Of a) m r

(为了清楚起见,typevar已重命名,请参阅effects的文档(,而f3不进行种类检查。

感觉就像你在试图击败流媒体的。你构建了管道,从源到汇,并运行它——关键是没有(隐含的(中间值积累。你的问题有点松散,因此准确地回答是不同的,但如果你想运行第一个流的所有效果,然后运行第二个流的全部效果,那么你必须愿意存储(表示第二个的计算(第二个流量,直到第一个流完成效果=>你已经累积了第二个数据流(因此并没有真正流化它(。因此,S.copy被设计用于交织效果。参见这个github问题。

[对更新的响应]

我认为让你困惑的部分原因是,你使用的是纯流,在没有效果的情况下,限制的动机就不那么明显了。使用管道组件的标识符,而不是部分结果。同样在你的例子中,你应该组合折叠,例如

import qualified Control.Foldl as L
import qualified Streaming.Prelude as S
myStreamFn =
let movingAvg n = {-# ... #-}
combinedAcc = (,,) <$> L.minimum <*> L.maximum <*> movingAvg 10
in  S.print 
$  L.purely S.fold combinedAcc 
$  pullFromDatabase

你可能想考虑的另一个功能是S.store,例如

myStreamFn 
= pullFromDatabase
& S.store S.maximum
& S.store (L.purely S.fold L.minimum)
& S.store movingAvg
& S.print

最新更新