运行管道的基础monad

时间:2014-07-14 15:58:25

标签: haskell pipe

拥有以下有状态的消费者:

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

execStateT

的帮助下,将其转换为下一种方式的最佳方法是什么?
consumer2 :: Consumer a m b

2 个答案:

答案 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