为什么(>>)未定义为(*>)?

时间:2018-01-01 05:39:18

标签: haskell ghc

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>

2 个答案:

答案 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)

当然,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定律。因此,您建议的方法可能会使优化器更加努力,甚至可能会阻止它在某些情况下生成最佳代码。