5

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

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

4

1 回答 1

9

如果要在 monad 转换器中使用底层 monad,可以使用lift

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

在这种情况下,tStateT MyState,并且mMyMonad。因此,例如:

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

Monad 转换器并不是“分层”的,因为你会MyMonad MyType从内部返回一个类型的值。这是一个更直接的转换:他们将一个 monad 变成一个新的,能够在转换后的 monad 中运行动作。因此,您可以将其StateT s m视为常规State smonad,除了您还可以使用lift将 action in 运行m为 action in之外StateT s m

如果您使用的是标准的Monad Transformer Library (mtl) 转换器,例如StateT,ReaderT等,您实际上不必使用lift; 在堆栈中的某个地方使用正确的变压器在任何modify单子中ask工作。(堆栈只是转换后的 monad 的塔,例如.)StateT s (ReaderT r IO)

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

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

所以liftIO (putStrLn "Hello, world!")适用于IO, StateT Int IO, ContT r (WriterT [String] IO), 等等。

(作为附加说明,foo这里实际上不是一个函数;更准确的术语是actioncompute。)

于 2012-01-20T15:35:28.963 回答