`(<*>) = 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
以及这种转换如何让我们从 Validation
的 Monad
实例的实际效果中恢复过来;我最常想做的是尽可能地积累错误,但仍然能够在必要时使用 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 中,因此它可以被覆盖以提高效率,而这从来没有完全进入文档。
所以如果 是 的情况,那么我猜 Monad
和 Applicative
的关系实际上是这样的:
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 m
和 Applicative m
- 如果没有 <*> = ap
和 pure = return
这两个定律,则无法保证这些结构一致。例如,列表使用 'regular' Monad
实例,列表使用 Applicative
实例。虽然 'wrong' Monad
和 Applicative
实例不一致,但它可能会让大多数用户感到困惑,因此它被 Monad
法律禁止。
tl;dr 所讨论的法律用于确保 Monad
和 Applicative
以直观明显的方式达成一致。
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
以及这种转换如何让我们从 Validation
的 Monad
实例的实际效果中恢复过来;我最常想做的是尽可能地积累错误,但仍然能够在必要时使用 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 中,因此它可以被覆盖以提高效率,而这从来没有完全进入文档。
所以如果 是 的情况,那么我猜 Monad
和 Applicative
的关系实际上是这样的:
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 ofap
" 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 ofap
. 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 m
和 Applicative m
- 如果没有 <*> = ap
和 pure = return
这两个定律,则无法保证这些结构一致。例如,列表使用 'regular' Monad
实例,列表使用 Applicative
实例。虽然 'wrong' Monad
和 Applicative
实例不一致,但它可能会让大多数用户感到困惑,因此它被 Monad
法律禁止。
tl;dr 所讨论的法律用于确保 Monad
和 Applicative
以直观明显的方式达成一致。