monad变换器堆栈中的evalState

时间:2017-09-11 15:53:26

标签: haskell monad-transformers state-monad

给定mtl monad堆栈,例如ExceptT String (WriterT String (State s a)),如何评估内部状态monad而无需打开外部monad?

have :: ExceptT String (WriterT String (State s)) a
f    :: State s a -> a

want :: ExceptT String (WriterT String Identity) a

我可以通过调用runExceptT后跟runWriterT然后重新打包结果来完成此操作,但这似乎是错误的方法。

就我的尝试而言,像fmap或类似的东西不起作用,因为monad变换器堆栈被视为一个完整的monad。我需要的是一个“拆分”monad变换器堆栈的功能,如下所示:

split :: (MonadTrans s, Monad t) => (s t) a -> s (t a)

要么我没有找到这个功能,要么解决方案完全不同。

2 个答案:

答案 0 :(得分:5)

我不知道任何与split一样通用的内容,但使用map...T函数可能会阻止显式操作:

have :: ExceptT String (WriterT String (State s)) a
f    :: State s a -> a

want :: ExceptT String (WriterT String Identity) a
want = mapExceptT (mapWriterT (return . f)) have

答案 1 :(得分:3)

在这种特殊情况下,最简单的方法是使用MFunctorExceptT e变换器的WriterT w个实例:

import Control.Monad.Morph

floop :: Monad m
      => s
      -> ExceptT e (WriterT w (StateT s m)) a
      -> ExceptT e (WriterT w m) a
floop s = hoist (hoist $ flip evalStateT s)

State s = StateT s Identity以来,上面的轻微概括是立竿见影的。