代码之家  ›  专栏  ›  技术社区  ›  Yolo Voe

为什么(>>)没有定义为(*>)?

  •  21
  • Yolo Voe  · 技术社区  · 7 年前

    GHC目前正在实施 >>

    (>>) :: m a -> m b -> m b
    m >> k = m >>= \_ -> k
    

    为什么不改为执行以下操作?

    (>>) :: m a -> m b -> m b
    m >> k = m *> k
    

    现在,我在想 >>= 做点什么 *> 不。

    但一切都是按语法进行的(比如,按类型),所以很难解释为什么它不起作用。 也许monad实例执行了一些应用程序实例没有执行的计算,但我认为这会破坏类型的语义。

    使现代化 我只能选择一个被接受的答案,但是 answer by dfeuer 非常有洞察力(特别是对于像我这样在Haskell方面相对缺乏经验的人)。

    2 回复  |  直到 7 年前
        1
  •  27
  •   castletheperson    7 年前

    根据 source code ,这是为了防止人们在重写时意外创建递归绑定 *> >> 在他们的 Applicative 例子

    (>>)        :: forall a b. m a -> m b -> m b
    m >> k = m >>= \_ -> k -- See Note [Recursive bindings for Applicative/Monad]
    

    便条上写着:

    注意:应用程序/Monad的递归绑定

    最初的申请/单子提案规定,在实施后,指定的实施(>)将成为

    (>>) :: forall a b. m a -> m b -> m b
    (>>) = (*>)
    

    默认情况下。您可能倾向于更改此选项以反映所述的建议,但您确实不应该这样做!为什么?因为人们倾向于 定义此类实例 另外 绕道而行:尤其是 定义Applicative实例完全合法 (*>) 在里面 条款 (>>) ,这将导致默认值的无限循环 Monad的实现!人们在野外也这样做。

    这变成了一个难以追踪的讨厌的bug 比起在上游各处消除它,只保留 原始默认值。

        2
  •  9
  •   dfeuer    7 年前

    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
    

    如您所见,这只使用一个绑定,而另一个使用两个绑定。根据单子恒等式定律,它们是等价的,但编译器不知道单子定律。因此,您建议的方法可能会使优化器工作更努力,甚至可能在某些情况下阻止它生成最佳代码。