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
是&#34; ap&#34;右边的简写。法律实际上表达了>>=
,return
和<*>
之间的关系吗?否则法律毫无意义。
上下文是我在考虑Validation
以及它似乎有一个合法的Monad
实例是多么令人不满意。我也在考虑ApplicativeDo
以及这种转变如何让我们从Monad
实例对Validation
的实际效果中恢复过来;我最常想做的是尽可能地累积错误,但仍然能够在必要时使用bind。我们实际上导出了bindV
函数,我们需要在任何地方使用它,这都是荒谬的。我能想到无法无天的唯一实际后果是,我们根据我们使用的构成类型(或者我们的程序在理论上如何通过重写规则进行转换)积累不同或更少的错误,尽管我不确定为什么应用组合会永远转变为monadic)。
编辑:Monad
中相同法律的文档更为广泛:
此外,Monad和Applicative操作应该如下:
pure = return (<*>) = ap
上述法律意味着:
fmap f xs = xs >>= return . f (>>) = (*>)
&#34;上述法律意味着......这里的想法是,这些是我们关心的真正法律吗?
但是现在我在Validation
的背景下试图理解这些。第一部法律将成立。如果我们只定义(>>) = (*>)
,显然可以保留第二个。
但是Monad
的文档令人惊讶地说明了>>
应该如何关联的任何事情(除非我只是错过了)。大概我们想要那个
a >> b = a >>= \_ -> b
...并且(>>)
包含在类中,以便可以覆盖它以提高效率,而这从未完全进入文档。
所以如果那个的情况,那么我猜Monad
和Applicative
关联的方式实际上是这样的:
return = pure
xs >>= return . f = fmap f xs
a >>= \_ -> b = fmap (const id) a <*> b
答案 0 :(得分:4)
因此,我认为
ap
法律中的(<*>) = ap
是&{34;ap
&#34;右侧的缩写。法律实际上表达了>>=
,return
和<*>
之间的关系吗?在我看来
(<*>) = ap
并不严格意味着任何事情(至少在AMP之后)。据推测,它试图在<*>
与ap
的右侧之间表达某种关系。也许我是迂腐的。
讽刺地说,我说的恰恰相反:因为ap
位于definitionally equal的右侧,说(<*>) = ap
与m1 <*> m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }
完全相同}。这只是处理这种平等的正常的第一步:扩展定义。
回复评论:
是的,但定义可以自由更改。
然后法律也会改变或被删除。就像将join
添加到Monad
时一样,当前的定义将成为法律。
根本不可能将其定义为
ap = <*>
你是说用这种方式定义ap
或法律是不可能的?
如果ap
,那么你是对的:它的类型错误。但是说这样的法律会很好。
答案 1 :(得分:4)
每个Monad
都会产生一个Applicative
,对于诱导Applicative
的{{1}},<*> = ap
将会定义。但鉴于两个结构 - Monad m
和Applicative m
- 如果没有两个法律<*> = ap
和pure = return
,则无法保证这些结构一致。例如,选择&#39;常规&#39;列表的Monad
实例和zip-list Applicative
实例。虽然没有什么从根本上是错误的&#39;关于Monad
和Applicative
实例的不同意见,它可能会让大多数用户感到困惑,因此Monad
法律禁止这样做。
tl; dr相关法律旨在确保Monad
和Applicative
以直观明显的方式达成一致。