Monad变换器内monad的结果

ael*_*ndy 5 haskell monad-transformers

这是我第一次认识Monad变形金刚,所以答案可能很明显.

假设我在StateT MyMonad MyType类型的do块中,我想创建相同类型的另一个函数,修改状态并返回MyMonad MyType类型的值.我怎样才能做到这一点?我想这里的例子在guessSession中显示,但我似乎无法理解如何应用它!

ehi*_*ird 9

如果要在monad变换器中使用基础monad,可以使用lift:

lift :: (MonadTrans t, Monad m) => m a -> t m a
Run Code Online (Sandbox Code Playgroud)

在这种情况下,tStateT MyState,mMyMonad.所以,例如:

foo :: StateT MyState MyMonad MyType
foo = do
  modify $ \s -> s+1
  lift $ doSomethingInMyMonad 42
Run Code Online (Sandbox Code Playgroud)

Monad变形金刚不是"分层"的,因为你MyMonad MyType从内部返回一个类型的值; 这是一个更直接的转换:它们将monad变成了一个能够在变换后的monad中运行动作的新monad.因此,您可以将其StateT s m视为常规State smonad,除了您还可以使用lift将操作m转换为操作StateT s m.

如果您使用的是标准的单子转换库(MTL)变压器一样StateT,ReaderT等等,你实际上并没有使用lift; 之类的东西modifyask工作在任何使用正确的变压器某处叠单子.(堆栈只是一个经过改造的monad塔,就像StateT s (ReaderT r IO).)

此外,如果您IO在底部有一个大堆栈,则可以使用便捷功能将IO操作提升到任意数量的层:

liftIO :: (MonadIO m) => IO a -> m a
Run Code Online (Sandbox Code Playgroud)

所以liftIO (putStrLn "Hello, world!")工作中IO,StateT Int IO,ContT r (WriterT [String] IO),等等.

(作为补充说明,foo这里实际上不是一个函数;更准确的术语是动作计算.)