Monad变换器内monad的结果

时间:2012-01-20 15:27:14

标签: haskell monad-transformers

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

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

1 个答案:

答案 0 :(得分:9)

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

lift :: (MonadTrans t, Monad m) => m a -> t m a

在这种情况下,tStateT MyStatemMyMonad。所以,例如:

foo :: StateT MyState MyMonad MyType
foo = do
  modify $ \s -> s+1
  lift $ doSomethingInMyMonad 42

Monad变换器不是“分层”,因为你从内部返回MyMonad MyType类型的值;它是一个更文字的转换:它们将monad变成一个新的monad,它能够在变换后的monad中运行动作。因此,您可以将StateT s m视为常规State s monad,除了您还可以使用liftm中执行转弯操作到StateT s m中的操作}。

如果您使用StateTReaderT等标准Monad Transformer Library(mtl)变换器,则实际上不必使用lift;像modifyask之类的东西在任何 monad中工作,并且堆栈中的某个地方有正确的变换器。 (堆栈只是一个变换的monad塔,如StateT s (ReaderT r IO)。)

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

liftIO :: (MonadIO m) => IO a -> m a

因此liftIO (putStrLn "Hello, world!")适用于IOStateT Int IOContT r (WriterT [String] IO),等等。

(另外请注意,foo这里实际上并不是一个功能;更准确的术语是动作计算。)