我正在尝试学习基于标准 Haskell 库的 monad 转换器(mtl?转换器?不确定我下载的 Haskell 平台 - 7.4.1 附带了哪一个)。
我相信我注意到的是每个 monad 转换器定义的通用结构:
例如,对于 Writer monad,会有:
这是monad转换器的组织方式吗?我遗漏了什么/我有任何不正确的细节吗?
这个问题的动机是弄清楚:
最佳答案
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
中声明的类型类.它的方法( writer
, pass
, tell
和 listen
)与 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
和其他人使用相同的架构。替换 Writer
与 State
你会得到State
的解释.
关于haskell - 单子(monad)变压器的解剖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13609626/