2014-07-14 14 views
3

具有以下状态消费者的基础单子:运行管

consumer1 :: Consumer a (StateT b m)() 

什么是将其转换为以下一个与execStateT帮助的最佳方式是什么?

consumer2 :: Consumer a m b 

回答

5

是否必须是execStateT?使用runStatePPipes.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的功能是伟大的,当你有一个管道供其不同的阶段有不同的效果。最好将效果限制在需要的管道的特定阶段。

+2

太棒了!实际上存在[一个'execStateP'函数](http://hackage.haskell.org/package/pipes-4.1.2/docs/Pipes-Lift.html#v:execStateP)。谢谢! –

+0

哦,我忘了'execStateP'。那么就更简单了。 – danidiaz

4

您可以使用丹尼达兹提到的中的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