gpt4 book ai didi

haskell - 为什么 Applicative 应该是 Monad 的父类(super class)?

转载 作者:行者123 更新时间:2023-12-03 06:41:19 26 4
gpt4 key购买 nike

给定:

Applicative m, Monad m => mf :: m (a -> b), ma :: m a

这似乎被认为是一项法律:

mf <*> ma === do { f <- mf; a <- ma; return (f a) }

或更简洁地说:

(<*>) === ap

documentation for Control.Applicative <*>是“顺序应用”,这表明 (<*>) = ap 。这意味着<*>必须从左到右顺序评估效果,以与 >>= 保持一致……但这感觉不对。 McBride and Paterson's original paper似乎暗示从左到右的排序是任意的:

The IO monad, and indeed any Monad, can be made Applicative by taking pure = return and <*> = ap. We could alternatively use the variant of ap that performs the computations in the opposite order, but we shall keep to the left-to-right order in this paper.

因此,<*>两个合法的、非平凡的推导。紧接着 >>=return ,具有独特的行为。在某些情况下,这两种派生都是不可取的。

例如,(<*>) === ap法律力量Data.Validation定义两种不同的数据类型:ValidationAccValidation 。前者有 Monad类似于 ExceptT 的实例,以及一致的Applicative实例的实用性有限,因为它在第一个错误后停止。另一方面,后者没有定义 Monad实例,因此可以自由地实现 Applicative更有用的是,它会累积错误。

有一些discussion about this previously在 StackOverflow 上,但我认为这并没有真正触及问题的核心:

为什么这应该成为一项法律?

仿函数、应用程序和单子(monad)的其他定律(例如恒等性、结合性等)表达了这些结构的一些基本数学属性。我们可以使用这些定律来实现各种优化,并使用它们来证明我们自己的代码。相比之下,我感觉就像 (<*>) === ap法律施加任意约束,却没有相应的好处。

无论如何,我宁愿放弃法律而选择这样的事情:

newtype LeftA m a = LeftA (m a)
instance Monad m => Applicative (LeftA m) where
pure = return
mf <*> ma = do { f <- mf; a <- ma; return (f a) }

newtype RightA m a = RightA (m a)
instance Monad m => Applicative (RightA m) where
pure = return
mf <*> ma = do { a <- ma; f <- mf; return (f a) }

我认为这正确地捕捉了两者之间的关系,而没有过度限制任何一方。

因此,可以从几个角度来解决这个问题:

  • 还有其他相关法律 MonadApplicative
  • 对于 Applicative 的排序效果是否存在任何固有的数学原因?就像他们对 Monad 所做的那样?
  • GHC 或任何其他工具是否执行假设/要求该定律成立的代码转换?
  • 为什么是 Functor-Applicative-Monad提案被认为是一件压倒性的好事吗? (如果有引用,我们将不胜感激)。

还有一个额外问题:

  • 怎么做AlternativeMonadPlus适合这一切吗?
<小时/>

注意:主要编辑是为了澄清问题的实质。 @duplode 发布的答案引用了早期版本。

最佳答案

嗯,我对到目前为止给出的答案不是很满意,但我认为附加的评论更有说服力。所以我在这里总结一下:

<小时/>

我认为只有一个明智的Functor来自 Applicative 的实例:

fmap f fa = pure f <*> fa

假设这是唯一的,那么 Functor 是有道理的应该是 Applicative 的父类(super class),根据该定律。同样,我认为只有一个明智的 Functor来自 Monad 的实例:

fmap f fa = fa >>= return . f

所以,Functor 是有道理的。应该是 Monad 的父类(super class)。我的反对意见(实际上仍然如此)是有两个合理的 Applicative Monad 之后的实例并且,在某些特定情况下,甚至更多是合法的;那么为什么要强制执行一项呢?

pigworker (original Applicative paper 上的第一作者)写道:

"Of course it doesn't follow. It's a choice."

(on twitter): "do-notation is unjust punishment for working in a monad; we deserve applicative notation"

duplode同样写道:

"... it is fair to say that pure === return and (<*>) === ap aren't laws in the strong sense that e.g. the monad laws are so ..."

"On the LeftA/RightA idea: there are comparable cases elsewhere in the standard libraries (e.g. Sum and Product in Data.Monoid). The problem of doing the same with Applicative is that the power-to-weight relation is too low to justify the extra precision/flexibility. The newtypes would make applicative style a lot less pleasant to use."

因此,我很高兴看到明确说明该选择,并通过简单的推理证明其合理性,即它使最常见的情况变得更容易。

关于haskell - 为什么 Applicative 应该是 Monad 的父类(super class)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24112786/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com