Monad变压器的解剖

我试图学习基于标准Haskell库(mtl?变换器?不知道哪一个随我下载了Haskell平台 - 7.4.1)的monad变换器。

我相信我已经注意到每个monad变压器定义的通用结构:

  • 基本类型('基本')

  • Monad实例
  • 变压器类型('BaseT')

  • Monad实例

  • MonadTrans实例

  • MonadIO实例

  • 变压器类('MonadBase')

  • 一些操作

  • 其他'BaseT's的实例

  • 举个例子,对于Writer monad来说,会出现:

  • Writer数据类型/ newtype / type,以及Monad实例
  • WriterT数据类型/ newtype / type,包含Monad,MonadTrans和MonadIO实例
  • 一个MonadWriter类,以及StateT,ReaderT,IdentityT这个类的实例...
  • 这是如何monad变压器组织? 我错过了什么/我有任何不正确的细节?

    这个问题的动机是搞清楚:

  • “BaseT”与相应的“MonadBase”和“Base”之间的关系和区别
  • 是否所有三个都是必需的
  • MonadTrans如何关联以及它的目的是什么

  • mtl包不会实现monad变换器。 至少WriterT只是从transformers重新出口。

    transformers包实现WriterT ,它本身就是一个单体变压器。 Writer只是一个别名:

    type Writer w = WriterT w Identity
    

    有些库可以单独实现Writer ,但无论如何这只是WriterT 。 ( Identity是一个微不足道的monad,它没有任何额外的行为。)

    MonadTrans允许您将底层monad包装到转换后的monad中。 你可以没有它,但你需要(见执行手动包装MonadTrans例如定义WriterT例如如何做到这一点)。 您真正需要MonadTrans的唯一用例 - 当您不知道变压器的实际类型时。

    MonadWriter是以mtl声明的类型类。 它的方法( writerpasstelllisten )与WriterT功能相同。 它允许通过堆栈变换器来自动换行(自动!) WriterT计算,即使您不知道堆栈中变压器的确切类型(甚至数字!)。

    所以WriterT是唯一需要的类型。

    对于其他monad变换器,它是相同的: BaseT是变换器, Base是没有底层monad的monad, MonadBase是所有monad的类类,它们在变换器栈中有BaseT

    添加:

    你可以在RWH书中找到很好的解释

    这是一个基本的例子:

    import Control.Monad.Trans
    import Control.Monad.Trans.Writer
    import Control.Monad.Trans.Reader hiding (ask)
    
    -- `ask` from transformers
    -- ask :: Monad m => ReaderT r m r
    import qualified Control.Monad.Trans.Reader as TransReader (ask)
    
    -- `ask` from mtl
    -- ask :: MonadReader r m => m r
    import qualified Control.Monad.Reader as MtlReader (ask)
    
    -- Our monad transformer stack:
    -- It supports reading Int and writing String
    type M m a = WriterT String (ReaderT Int m) a
    
    -- Run our monad
    runM :: Monad m => Int -> M m a -> m (a, String)
    runM i action = runReaderT (runWriterT action) i
    
    test :: Monad m => M m Int
    test = do
      tell "hello"
      -- v <- TransReader.ask     -- (I) will not compile
      v1 <- lift TransReader.ask  -- (II) ok
      v2 <- MtlReader.ask         -- (III) ok
      return (v1 + v2)
    
    main :: IO ()
    main = runM 123 test >>= print
    

    请注意, (I)将被编译器拒绝(尝试查看错误消息!)。 但(II)编译,感谢MonadTrans (“显式提升”)。 感谢MonadReader(III)开箱即用(“隐式提升”)。 请阅读RWH书籍以了解它的工作原理。

    (在我们导入例如ask从两个不同的模块,这就是为什么我们需要合格的进口。通常你会在同一时间只能使用其中的一个。)

    我也不是故意专门询问Writer

    不知道我明白... ReaderState和其他人使用相同的模式。 用State代替Writer ,你将会得到State的解释。

    链接地址: http://www.djcxy.com/p/77363.html

    上一篇: Anatomy of a monad transformer

    下一篇: How to cleanly convert between lists and ListT monad transformers?