具有以下状态消费者的基础单子:运行管
consumer1 :: Consumer a (StateT b m)()
什么是将其转换为以下一个与execStateT
帮助的最佳方式是什么?
consumer2 :: Consumer a m b
具有以下状态消费者的基础单子:运行管
consumer1 :: Consumer a (StateT b m)()
什么是将其转换为以下一个与execStateT
帮助的最佳方式是什么?
consumer2 :: Consumer a m b
是否必须是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
的功能是伟大的,当你有一个管道供其不同的阶段有不同的效果。最好将效果限制在需要的管道的特定阶段。
您可以使用丹尼达兹提到的中的execStateP。
execStateP :: Monad m => s -> Proxy a' a b' b (StateT s m) r -> Proxy a' a b' b m s
编辑:
一般来说如果基单子是MFunctor
可以使用distribute
功能使底座单子到堆栈的顶部,那么你就可以在“运行”单子它消除那个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
如果你仔细定义你的单子堆栈中的MFunctor
限制可能被解除。因此,例如,在延续图层的每一侧都有一个精心定义的monad堆栈,并且可以定义一个distributeCont
,它将与延续变压器一起工作,该延续变压器不是MFunctor
。
太棒了!实际上存在[一个'execStateP'函数](http://hackage.haskell.org/package/pipes-4.1.2/docs/Pipes-Lift.html#v:execStateP)。谢谢! –
哦,我忘了'execStateP'。那么就更简单了。 – danidiaz