`(<*>) = ap` Applicative/Monad 定律究竟如何将这两个 类 联系起来?

How exactly does the `(<*>) = ap` Applicative/Monad law relate the two classes?

ap 没有记录在案的规范,阅读时有评论指出它可能是 <*>,但出于实际原因并非如此:

ap                :: (Monad m) => m (a -> b) -> m a -> m b
ap m1 m2          = do { x1 <- m1; x2 <- m2; return (x1 x2) }
-- Since many Applicative instances define (<*>) = ap, we
-- cannot define ap = (<*>)

所以我假设 (<*>) = ap 定律中的 ap 对于 "right-hand side of ap" 是 shorthand 并且该定律实际上表达了 >>=return<*> 对吗?否则法律没有意义。

上下文是我在考虑 Validation 以及它似乎没有合法的 Monad 实例是多么令人不满意。我也在考虑 ApplicativeDo 以及这种转换如何让我们从 ValidationMonad 实例的实际效果中恢复过来;我最常想做的是尽可能地积累错误,但仍然能够在必要时使用 bind。我们实际上导出了一个 bindV 函数,我们几乎在任何地方都需要使用它,这有点荒谬。我能想到的无法无天的唯一实际后果是,根据我们使用的组合类型(或者我们的程序在理论上如何通过重写规则进行转换,尽管我不确定为什么应用组合会永远存在),我们会累积不同或更少的错误转换为 monadic)。

编辑Monad中相同法律的文档更为广泛:

Furthermore, the Monad and Applicative operations should relate as follows:

pure = return
(<*>) = ap

The above laws imply:

fmap f xs  =  xs >>= return . f
(>>) = (*>)

"The above laws imply"...那么这里的想法是这些是我们关心的真正法律吗?

但现在我只能尝试在 Validation 的背景下理解这些内容。第一定律将成立。如果我们只定义 (>>) = (*>),显然可以使第二个成立。

但令人惊讶的是,Monad 的文档根本没有说明 >> 应该如何关联(除非我遗漏了它)。大概我们想要那个

a >> b = a >>= \_ -> b

...并且 (>>) 包含在 class 中,因此它可以被覆盖以提高效率,而这从来没有完全进入文档。

所以如果 的情况,那么我猜 MonadApplicative 的关系实际上是这样的:

return = pure
xs >>= return . f = fmap f xs
a >>= \_ -> b = fmap (const id) a <*> b

So I assume the ap in the (<*>) = ap law is shorthand for "right-hand side of ap" and the law actually expresses a relationship between >>=, return and <*> right?

It seems to me (<*>) = ap doesn't strictly imply anything (at least post-AMP). Presumably it's trying to express some relationship between <*> and the right-hand side of ap. Maybe I'm being pedantic.

迂腐地说,我会说相反的:因为ap在它的右边是definitionally equal,说(<*>) = ap和说[=21=是完全一样的].这只是处理此类等式的正常第一步:扩展定义。

回复评论:

Right, but the definition is free to change.

然后法律也会改变或被删除。正如 when/if join 添加到 Monad 一样,当前的定义将成为法律。

it wouldn't have been possible to define it literally as ap = <*>

你的意思是这样就无法定义 ap 或法则了?

如果ap,那么你是对的:它的类型是错误的。不过把法律说成这样就好了

每个 Monad 都会产生一个 Applicative,并且对于那个诱导的 Applicative<*> = ap 将在定义上成立。但是给定两个结构 - Monad mApplicative m - 如果没有 <*> = appure = return 这两个定律,则无法保证这些结构一致。例如,列表使用 'regular' Monad 实例,列表使用 Applicative 实例。虽然 'wrong' MonadApplicative 实例不一致,但它可能会让大多数用户感到困惑,因此它被 Monad 法律禁止。

tl;dr 所讨论的法律用于确保 MonadApplicative 以直观明显的方式达成一致。