首页 > 解决方案 > Pipes (Haskell lib) - 具有不同状态单子的管道管道

问题描述

我的目标是使最后产生的值等于 80 (40 + 40)(参见下面的代码)...

import Pipes
import Pipes.Prelude
import Pipes.Lift
import Control.Monad.State.Strict

data Input = A Integer | B Integer | C Integer

main :: IO ()
main = runEffect $ each [A 10,B 2,C 3,A 40,A 40] >-> pipeline >-> print


pipeline :: Pipe Input Integer IO ()
pipeline = for cat $ \case
  A x -> yield x >-> accumulate
  B x -> yield x
  C x -> yield x

accumulate :: Pipe Integer Integer IO ()
accumulate = evalStateP 0 accumulate'


accumulate' :: Pipe Integer Integer (StateT Integer IO) ()
accumulate' = go
  where
    go = do
        x <- await
        lift $ modify (+x)
        r <- lift get
        yield r
        go

在这个例子中, Input As 没有累积......yield x >-> accumulate在 Input A 上确实做了我所期望的,流每次都是一个新的......

按顺序使用不同状态单子的管道管道效果很好,但在这里我想以某种方式将它们嵌套在案例模式中(就像子流一样)......

标签: haskellhaskell-pipes

解决方案


问题是你调用evalStateP得太早了,丢弃了你想要在调用中保留的状态accumulate。尝试这样的事情:

pipeline :: Pipe Input Integer IO ()
pipeline = evalStateP 0 $ for cat $ \case
  A x -> yield x >-> accumulate
  B x -> yield x
  C x -> yield x

accumulate :: Pipe Integer Integer (StateT Integer IO) ()
accumulate = for cat $ \x -> do
        modify (+x)
        r <- get
        yield r

请注意,它Proxy有一个MonadState实例,因此如果您使用mtl.


推荐阅读