如何折叠流数据?

时间:2017-08-16 19:59:24

标签: haskell frp

我正在尝试在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。但我不知道在这种情况下如何做到这一点。我的简单定义是否可以实现这一点,还是需要不同的东西?感谢。

1 个答案:

答案 0 :(得分:2)

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'