haskell - 单子(monad)变压器的解剖

标签 haskell monads monad-transformers

我正在尝试学习基于标准 Haskell 库的 monad 转换器(mtl?转换器?不确定我下载的 Haskell 平台 - 7.4.1 附带了哪一个)。

我相信我注意到的是每个 monad 转换器定义的通用结构:

  • 基本类型(“基本”)
  • Monad 实例
  • 变压器类型('BaseT')
  • Monad 实例
  • MonadTrans 实例
  • MonadIO 实例
  • 变压器类('MonadBase')
  • 一些操作
  • 其他 'BaseT's
  • 的实例

    例如,对于 Writer monad,会有:
  • 一个 Writer 数据类型/新类型/类型,带有一个 Monad 实例
  • 一个 WriterT 数据类型/新类型/类型,带有 Monad、MonadTrans 和 MonadIO 实例
  • 一个 MonadWriter 类,以及 StateT、ReaderT、IdentityT 的此类实例...

  • 这是monad转换器的组织方式吗?我遗漏了什么/我有任何不正确的细节吗?

    这个问题的动机是弄清楚:
  • “BaseT”与相应的“MonadBase”和“Base”之间有什么关系和区别
  • 三个都需要
  • MonadTrans 是如何相关的,它的目的是什么
  • 最佳答案

    mtl包没有实现 monad 转换器。至少 WriterT 只是 reexported来自 transformers .
    transformers包工具WriterT ,它本身就是一个单子(monad)变压器。 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 和 MonadBase 的 monad是一个类型类——所有 monad 的类,具有 BaseT在变压器堆栈的某个地方。

    已添加:

    您可以在 RWH book 中找到很好的解释

    这是一个基本示例:
    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,这就是我们需要限定导入的原因。通常一次只使用其中一个。)

    Also I didn't mean to specifically ask about Writer.



    不知道我明白... Reader , State和其他人使用相同的架构。替换 WriterState你会得到State的解释.

    关于haskell - 单子(monad)变压器的解剖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13609626/

    相关文章:

    haskell - 无法将 LoggingT 与 NoLoggingT 匹配

    haskell - 为所有 MonadTrans 实例提供类型类实例

    parsing - 语法歧义: why?(问题是: "(a)"与 "(a-z)")

    带修复的 Haskell AST 注释

    haskell - 用户损坏、Data.Binary 损坏或安装损坏?

    haskell - 如何在 Haskell 中实现实际解​​析已经完成的 Read 实例?

    scala - 在 Scala 中将(任一 future 的列表)转换为(任一列表的 future )

    monads - 为什么在编写新的 Monad Transformers 时使用样板

    javascript - JavaScript 中的生成器函数和 monad 之间有什么联系?

    haskell - 为什么电梯的返回值不被限制为单子(monad)?