【发布时间】:2012-10-19 06:13:23
【问题描述】:
我是 Haskell 的新手,但了解如何使用 Monad Transformers。 然而,我仍然难以抓住他们声称的将参数传递给函数调用的优势。
基于wiki Monad Transformers Explained,我们基本上有一个配置对象定义为
data Config = Config Foo Bar Baz
并传递它,而不是使用此签名编写函数
client_func :: Config -> IO ()
我们使用 ReaderT Monad Transformer 并将签名更改为
client_func :: ReaderT Config IO ()
然后拉动配置只是调用ask。
函数调用从client_func c变为runReaderT client_func c
很好。
但是为什么这会让我的应用程序更简单呢?
1- 当您将许多功能/模块组合在一起以形成应用程序时,我怀疑 Monad Transformers 会产生兴趣。但这就是我的理解停止的地方。有人可以阐明一下吗?
2- 我找不到任何关于如何在 Haskell 中编写大型 模块化 应用程序的文档,其中模块公开某种形式的 API 并隐藏它们的实现,以及(部分)隐藏它们自己的来自其他模块的状态和环境。请大家指点一下?
(编辑:Real World Haskell 声明“.. 这种方法 [Monad Transformers] ......适用于更大的程序。”,但没有明确的例子证明这种说法)
在下面的 Chris Taylor 回答之后编辑
Chris 完美地解释了为什么在 Transformer Monad 中封装 Config、State 等会带来两个好处:
- 它可以防止更高级别的函数必须在其类型签名中维护它调用的(子)函数所需但它自己使用不需要的所有参数(请参阅
getUserInput函数) - 因此,更高级别的函数对 Transformer Monad 内容的更改更具弹性(假设您想在其中添加
Writer以在较低级别的函数中提供日志记录)
这是以更改所有函数的签名为代价的,以便它们“在”Transformer Monad 中运行。
所以问题 1 已完全涵盖。谢谢克里斯。
问题 2 现已在this SO post得到解答
【问题讨论】:
-
当您暂时需要某些 monad 的功能时,Transformers 也很有用,用于子计算。例如,我使用
WriterT记录信息,同时使用State生成的唯一标识符更新数据结构。
标签: haskell monad-transformers