GHC目前实施>>
为
(>>) :: m a -> m b -> m b
m >> k = m >>= \_ -> k
为什么不这样做呢?
(>>) :: m a -> m b -> m b
m >> k = m *> k
现在,我在想>>=
做*>
没有做的事。
但是所有的东西都是按语法编写的(例如,类型方面),因此很难说明为什么它不起作用。 也许monad实例做了一些应用实例没有的计算,但我认为这会破坏该类型的语义。
更新我只能选择一个接受的SO答案,但answer by dfeuer非常有洞察力(特别是对于像我这样在Haskell中相对缺乏经验的人)。< / p>
答案 0 :(得分:27)
根据source code中的评论,如果他们在*>
中覆盖>>
为Applicative
,则会阻止人们意外创建递归绑定实例
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k -- See Note [Recursive bindings for Applicative/Monad]
说明说:
注意:Applicative / Monad
的递归绑定最初的Applicative / Monad提案表明,实施后,(&gt;&gt;)的指定实施将成为
(>>) :: forall a b. m a -> m b -> m b (>>) = (*>)
默认情况下。你可能倾向于改变这个以反映所提出的建议,但你真的不应该!为什么?因为人们倾向于 定义这样的实例其他方式:特别是,它是 完全合法地定义Applicative
(*>)
的实例(>>)
的术语,这将导致默认的无限循环 Monad的实施!人们在野外这样做。这变成了一个令人讨厌的错误,而且很难找到 而不是在上游的任何地方消除它,它更容易保留 原始默认值。
答案 1 :(得分:9)
Monad
实例都支持Applicative
实例比liftA2 = liftM2
更高效。也就是说,
liftA2 f xs ys = xs >>= \x -> ys >>= \y -> pure (f x y)
使用默认(*>) = liftA2 (flip const)
给出
xs *> ys = xs >>= \ _ -> ys >>= \y -> pure y
另一方面,(>>)
的默认定义为
xs >> ys = xs >>= \ _ -> ys
如您所见,这只使用一个绑定,而另一个使用两个绑定。根据monad身份法,它们是等价的,但编译器不知道monad定律。因此,您建议的方法可能会使优化器更加努力,甚至可能会阻止它在某些情况下生成最佳代码。