【发布时间】:2019-09-11 19:47:20
【问题描述】:
阅读了http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors,我可以提供一个使用函数作为应用函子的例子:
假设 res 是一个有 4 个参数的函数,fa、fb、fc、fd 都是采用单个参数的函数。那么,如果我没记错的话,这个适用的表达方式:
f <$> fa <*> fb <*> fc <*> fd $ x
意思和这个非花哨的表达一样:
f (fa x) (fb x) (fc x) (fd x)
呃。我花了相当多的时间来理解为什么会这样,但是 - 在一张纸和我的笔记的帮助下 - 我应该能够证明这一点。
然后我读到了http://learnyouahaskell.com/for-a-few-monads-more#reader。我们又回到了这个问题上,这次是单子语法:
do
a <- fa
b <- fb
c <- fc
d <- fd
return (f a b c d)
虽然我需要另一张 A4 纸来证明这一点,但我现在非常有信心,这再次意味着相同:
f (fa x) (fb x) (fc x) (fd x)
我很困惑。为什么?这有什么用?
或者,更准确地说:在我看来,这只是将函数的功能复制为应用程序,但语法更冗长。
那么,你能给我举个例子,说明 Reader monad 可以做 applicatives 做不到的吗?
实际上,我还想问一下这两个函数有什么用:应用函数或 Reader monad - 因为虽然能够将相同的参数应用于四个函数(fa,fb , fc, fd) 不重复这个论点四次确实减少了一些重复性,我不确定这个微小的改进是否能证明这种复杂程度的合理性;所以我想我一定错过了一些突出的东西;但这值得一个单独的问题
【问题讨论】:
-
不,它不等同于
f (fa x) (fb x) (fc x) (fd x)。do符号是语法糖,这意味着你写了fa >>= \a -> fb >>= \b -> fc >>= \c -> fd >>= \d -> return (f a b c d)。请注意,>>=取决于 monad 会做不同的事情。 -
@WillemVanOnsem 是的,我知道 do 符号是你所写内容的同步糖;但是,在填写了一张 A4 纸后,我有理由确定在 READER MONAD 的情况下(不是任何 monad)
fa >>= \a -> fb >>= \b -> fc >>= \c -> fd >>= \d -> return (f a b c d)实际上等同于f (fa x) (fb x) (fc x) (fd x) -
这是一个公平的问题,但你可以对许多 monad 提出同样的问题——你可以用 monad 做的一些事情也可以用 applicative 来做。但相当多的不能(遗憾的是,我没有一个很好的例子,但我相信会有比我更专业的人),不幸的是 LYAH 选择了一个可能是的例子而是以应用表示法完成。
-
Reader amonad 和(->) amonad 是同构的。它们之间的区别只是一个包装构造函数。你可以根据“口味”来选择,可以这么说。我猜Reader a使用得更多,因为它有一个名字,而且包装有助于理解什么是单子函数,什么是常规函数。 -
虽然一般
Monad比Applicative更强大(如chepner 的回答中所解释的),Reader/function 函子是一个非常特殊的情况,其中Monad和@987654350 @ 实例恰好是等价的——参见this answer of mine 的第二部分。 (抄送@RobinZigmond)
标签: haskell monads applicative reader-monad