0

在 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]]

请注意,上面的结果中没有更多的 ':>'。更一般地说,我不确定是否有函数可以“简化”嵌套流(或流的流)来自m(Of a)参与Stream (Of a) m r

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

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

4

1 回答 1

3
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

(为清楚起见重命名了类型变量,请参阅文档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
于 2020-02-18T22:27:04.403 回答