【问题标题】:How can I fold streaming data?如何折叠流数据?
【发布时间】:2017-08-16 19:59:24
【问题描述】:

我正在尝试在 Haskell 中实现功能性反应流。我有一个相当简单的定义:

data Observer a = Observer { next :: a -> IO () }
data Stream a = Stream { subscribe :: Observer a -> IO () }

instance Functor Stream where
    fmap = mapStream

mapStream :: (a -> b) -> Stream a -> Stream b
mapStream f Stream{ subscribe=s } = Stream {
        subscribe = \Observer{ next=n } -> s Observer{ next = \a -> n $ f a }
    }

 fromArray :: [a] -> Stream a
 fromArray arr = Stream {
        subscribe = \Observer{ next=n } -> forM_ arr n
    }

这对于像上面的fmap 这样的简单运算符非常有效。我的问题是我将如何为此实施foldStream?我无法更改值,因此我将不得不使用新的种子值递归调用 foldStream。但我不知道如何在这种情况下做到这一点。这甚至可以通过我的简单定义实现,还是我需要一些不同的东西?谢谢。

【问题讨论】:

  • foldStream 会有什么类型?
  • 大概是foldStream :: (a -> b -> b) -> b -> Stream a -> Stream b
  • 就像数组的折叠:foldStream :: (b -> a -> b) -> b -> Stream a -> Stream b

标签: haskell frp


【解决方案1】:

foldStream 跟踪状态。您必须将该状态放在某处,例如 IORef

import Data.IORef

foldStream :: (a -> b -> b) -> b -> Stream a -> Stream b
foldStream f z source = Stream $ \observer -> do
    ref <- newIORef z
    subscribe source $ Observer $ \a -> do
        b <- readIORef ref
        let b' = f a b
        writeIORef ref b'
        next observer b'

【讨论】:

  • 谢谢,我已经猜到我必须使用 state monad 或类似的东西。只是想确定没有一种聪明的方法可以为此使用递归
猜你喜欢
  • 2018-11-20
  • 2023-03-25
  • 1970-01-01
  • 2013-12-13
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 2016-08-02
  • 2012-07-07
相关资源
最近更新 更多