为什么(>>)没有定义为(*>)?
GHC目前实施>>
为
(>>) :: m a -> m b -> m b
m >> k = m >>= _ -> k
为什么不做以下改为?
(>>) :: m a -> m b -> m b
m >> k = m *> k
现在,我正在思考>>=
做些什么*>
没有。
但是,所有的东西都是语法的(例如,类型),所以很难理解它为什么不起作用。 也许monad实例做了一些计算,但应用实例没有,但我认为这会打破该类型的语义。
更新我只能选择一个如此接受的答案,但dfeuer的答案非常有见地(特别是对于像我这样的人,在Haskell中相对缺乏经验的人)。
根据源代码中的评论,这是为了防止人们在Applicative
实例中重写*>
as >>
意外创建递归绑定。
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= _ -> k -- See Note [Recursive bindings for Applicative/Monad]
该说明说:
注意:Applicative / Monad的递归绑定
最初的Applicative / Monad提案指出,实施后,(>>)的指定实施将成为
(>>) :: forall a b. m a -> m b -> m b
(>>) = (*>)
默认。 你可能倾向于改变这一点以反映所提出的建议,但你真的不应该这样做! 为什么? 因为人们倾向于用另一种方式定义这样的实例:特别是,根据(>>)
定义Applicative (*>)
的实例是完全合法的,这将导致Monad的默认实现的无限循环! 人们在野外这样做。
这变成了一个棘手的错误追踪,而不是消除它在上游的任何地方,保留原始默认值更容易。
4castle的答案当然是对的,但还有一件事需要考虑。 并非每个Monad
实例都支持比liftA2 = liftM2
更高效的Applicative
实例。 那是,
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
正如你所看到的,这只使用一个绑定,而另一个使用两个绑定。 按照单子身份法,它们是等价的,但编译器不知道单子法。 因此,您建议的方法可能会使优化器工作更加困难,甚至可能会阻止它在某些情况下生成最佳代码。
链接地址: http://www.djcxy.com/p/107.html