我正在尝试基于标准的Haskell库学习monad转换器(Mtl?转换器?不确定我下载的Haskell平台7.4.1附带了哪一个)。
我相信我注意到的是每个monad变压器定义的通用结构:
因此,例如,对于Writer monad,将有:
这是monad变压器的组织方式吗?我是否遗漏任何东西/我有任何不正确的详细信息吗?
这个问题的动机是弄清楚:
最佳答案
mtl
包未实现monad转换器。至少WriterT只是transformers
中的reexported。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的monad,MonadBase
是类型类-所有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
,这就是为什么我们需要合格的导入。通常您一次只能使用其中一个。)不确定我了解...
Reader
,State
和其他人使用相同的架构。用Writer
替换State
,您将获得State
的说明。关于haskell - monad变压器的解剖,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13609626/