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中相对缺乏经验的人)。
根据source code的评论,如果他们在*>
实例中将>>
重写为Applicative
,则可以防止人们意外地创建递归绑定。
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k -- See Note [Recursive bindings for Applicative/Monad]
说明说:
Note: Recursive bindings for Applicative/Monad
最初的Applicative / Monad提案表明,实施后,(>>)的指定实施将成为
(>>) :: forall a b. m a -> m b -> m b (>>) = (*>)
默认情况下。你可能倾向于改变这个以反映所陈述的提议,但你真的不应该!为什么?因为人们倾向于以相反的方式定义这样的实例:特别是,根据
(*>)
定义Applicative(>>)
的实例是完全合法的,这将导致Monad的默认实现的无限循环!人们在野外做这件事。这变成了一个令人讨厌的错误,它很难追踪,而不是在上游到处消除它,它更容易保留原始默认值。
当然,4castle的回答是对的,但还有另外一件事要考虑。并非每个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定律。因此,您建议的方法可能会使优化器更加努力,甚至可能会阻止它在某些情况下生成最佳代码。