如何使用管道(Pipes)和状态(State)?

6
我有一个函数,类型为Map Int String -> Proxy () a () Void IO b。现在它await,对获取到的值进行操作,然后重新调用自身。我想改为使用State (Map Int String)而不是将其作为参数传递,这样我就可以只使用forever,而不需要每个分支都记得递归。我知道我需要使用StateTState与另一个单子结合起来,但我不明白StateT在该类型签名中属于哪里,或者是否需要liftget这样的函数。一个既是State (Map Int String)又是Proxy () a () Void IO b的函数的正确类型是什么?

希望这可以帮到你! - user3303858
1个回答

16

注意: Proxy () a () Void = Consumer a,因此在本答案中我将称之为Consumer

简单的方法是将你的StateT单子变换层放在Consumer层之外,然后立即运行它。这里有一个例子:

import Control.Monad (forever)
import Control.Monad.Trans.State.Strict
import Pipes

example :: (Show a) => Consumer a IO r
example = flip evalStateT 0 $ forever $ do
    -- Inside here we are using `StateT Int (Consumer a IO) r`
    a <- lift await
    n <- get
    lift $ lift $ putStrLn $ "Received value #" ++ show n ++ ": " ++ show a
    put (n + 1)

...这是它在使用中的表现:

>>> runEffect $ each ["Test", "ABC"] >-> example
Received value #0: "Test"
Received value #1: "ABC"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接