【问题标题】:Result of monad inside monad transformermonad 转换器内部的 monad 结果
【发布时间】:2012-01-20 15:27:13
【问题描述】:

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

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

【问题讨论】:

标签: haskell monad-transformers


【解决方案1】:

如果你想在一个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 中运行动作。因此,您可以将StateT s m 视为常规的State s monad,除了您还可以使用liftm 中的操作转换为StateT s m 中的操作。

如果您使用标准的Monad Transformer Library (mtl) 转换器,例如StateTReaderT 等,您实际上不必使用liftmodifyask 之类的东西在 any 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 这里实际上并不是一个函数;更准确的术语是 actioncomputation。)

【讨论】:

  • 我想我明白了。只是为了完全清楚。想象一下,我在添加 StateT 之前做了一个
  • @aelguindy:是的!如果你有一段代码只使用了MyMonad,你也可以提升整个do块:lift $ do ...
  • 谢谢!不确定这是否是正确的提问地方,但是否有与 lift 相同但有 2 个参数的 lift2 ? 愚蠢的问题!找到答案
  • @aelguindy:它会做什么?如果你想使用像f :: T1 -> T2 -> MyMonad T3 这样的函数,你可以直接使用lift (f a b)(相当于:lift $ f a b)。 lift 根本不提升函数,只是单子计算。
  • 正要说我想到了!再次感谢 :-)。我想我现在完全明白了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 2021-11-27
  • 2018-02-06
  • 2013-05-01
  • 2021-12-11
相关资源
最近更新 更多