给定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)
要么我没有找到这个功能,要么解决方案完全不同。
答案 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)
在这种特殊情况下,最简单的方法是使用MFunctor
和ExceptT 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
以来,上面的轻微概括是立竿见影的。