拥有以下有状态的消费者:
consumer1 :: Consumer a (StateT b m) ()
在execStateT
?
consumer2 :: Consumer a m b
答案 0 :(得分:5)
是否必须execStateT
?使用runStateP
中的Pipes.Lift
可以更轻松地完成此操作。
import Pipes
import Pipes.Lift
import Control.Monad.State.Strict
-- unnecessarily specific signature, function work with any Proxy
foo :: Monad m => b -> Consumer a (StateT b m) () -> Consumer a m b
foo b p = liftM snd $ runStateP b p
当您拥有不同阶段具有不同效果的管道时,Pipes.Lift
中的功能非常好。最好将效果限制在需要的管道的特定阶段。
答案 1 :(得分:4)
您可以在danidiaz提到的execStateP中使用Pipes.Lift
。
execStateP :: Monad m => s -> Proxy a' a b' b (StateT s m) r -> Proxy a' a b' b m s
编辑:
一般情况下,如果基本monad是MFunctor
,你可以使用distribute
函数将基本monad带到堆栈的顶部,然后你可以“运行”monad它消除了monad层
distribute
:: (Monad m, Monad (t m), Monad (t (Proxy a' a b' b m)),
MonadTrans t, MFunctor t) =>
Proxy a' a b' b (t m) r -> t (Proxy a' a b' b m) r
以execStateT
为例:
> :t S.execStateT . distribute
S.execStateT . distribute
:: Monad m =>
Proxy a' a1 b' b (S.StateT s m) a -> s -> Proxy a' a1 b' b m s
如果您仔细定义monad堆栈,则可以解除MFunctor
限制。因此,例如,通过精心定义的monad堆栈,在延续层的每一侧都有一个管道层,您可以定义distributeCont
,它将与延续变换器一起使用,而不是MFunctor
。