GHC目前实施>>为
(>>) :: m a -> m b -> m b
m >> k = m >>= \_ -> k
Run Code Online (Sandbox Code Playgroud)
为什么不这样做呢?
(>>) :: m a -> m b -> m b
m >> k = m *> k
Run Code Online (Sandbox Code Playgroud)
现在,我在想>>=什么*>都没有.
但是所有的东西都是按语法编写的(如在类型方面),所以很难说明为什么它不起作用.也许monad实例做了一些应用实例没有的计算,但我认为这会破坏该类型的语义.
4ca*_*tle 27
根据在注释的源代码,这是为了防止人们意外地创建一个递归的,如果他们重写结合*>作为>>他们的Applicative实例.
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k -- See Note [Recursive bindings for Applicative/Monad]
Run Code Online (Sandbox Code Playgroud)
说明说:
注意:Applicative/Monad的递归绑定
最初的Applicative/Monad提案表明,实施后,(>>)的指定实施将成为
Run Code Online (Sandbox Code Playgroud)(>>) :: forall a b. m a -> m b -> m b (>>) = (*>)默认情况下.你可能倾向于改变这个以反映所陈述的提议,但你真的不应该!为什么?因为人们往往定义此类情况下,其他各地方式:尤其是,这是完全合法的定义一个应用型的实例
(*>)来讲(>>),这将导致对单子的默认实现无限循环!人们在野外做这件事.这变成了一个令人讨厌的错误,它很难追踪,而不是在上游到处消除它,它更容易保留原始默认值.
当然,4castle的回答是对的,但还有另外一件事要考虑.并非每个Monad实例都支持比Applicative实例更高效的实例liftA2 = liftM2.那是,
liftA2 f xs ys = xs >>= \x -> ys >>= \y -> pure (f x y)
Run Code Online (Sandbox Code Playgroud)
使用默认值(*>) = liftA2 (flip const)给出
xs *> ys = xs >>= \ _ -> ys >>= \y -> pure y
Run Code Online (Sandbox Code Playgroud)
另一方面,(>>)给出的默认定义
xs >> ys = xs >>= \ _ -> ys
Run Code Online (Sandbox Code Playgroud)
如您所见,这只使用一个绑定,而另一个使用两个绑定.根据monad身份法,它们是等价的,但编译器不知道monad定律.因此,您建议的方法可能会使优化器更加努力,甚至可能会阻止它在某些情况下生成最佳代码.