【问题标题】:Is `x >> pure y` equivalent to `liftM (const y) x``x >> pure y` 是否等同于 `liftM (const y) x`
【发布时间】:2019-08-18 10:29:30
【问题描述】:

两种表达方式

y >> pure x
liftM (const x) y

在 Haskell 中具有相同的类型签名。 我很好奇它们是否等价,但我既无法证明这一事实,也无法举出反例。

如果我们重写这两个表达式,从而消除xy,那么问题就变成了以下两个函数是否等价

flip (>>) . pure
liftM . const

请注意,这两个函数的类型均为 Monad m => a -> m b -> m a

我使用 Haskell 为 monad、applicatives 和 functors 提供的定律将这两个语句转换为各种等价形式,但我无法在两者之间产生一系列等价。

比如我发现y >> pure x可以改写如下

y >>= const (pure x)
y *> pure x
(id <$ y) <*> pure x
fmap (const id) y <*> pure x

liftM (const x) y可以改写如下

fmap (const x) y
pure (const x) <*> y

在我看来,这些都不是必然等价的,但我想不出它们不等价的任何情况。

【问题讨论】:

    标签: haskell monads functor applicative


    【解决方案1】:

    是的,它们是一样的

    让我们从flip (&gt;&gt;) . pure开始,这是您提供的x &gt;&gt; pure y的免积分版本:

    flip (>>) . pure
    

    flip (&gt;&gt;) 就是 (=&lt;&lt;) . const,所以我们可以重写为:

    ((=<<) . const) . pure
    

    由于函数组合 ((.)) 是关联的,我们可以这样写:

    (=<<) . (const . pure)
    

    现在我们想重写const . pure。我们可以注意到const 只是pure(a -&gt;) 上,这意味着因为pure . purefmap pure . pureconst . pure(.) pure . const,((.)fmap 对于函子@987634 )。

    (=<<) . ((.) pure . const)
    

    现在我们再次关联:

    ((=<<) . (.) pure) . const
    

    ((=&lt;&lt;) . (.) pure)liftM1 的定义,所以我们可以替换:

    liftM . const
    

    这就是目标。两者是一样的。


    1:liftM的定义是liftM f m1 = do { x1 &lt;- m1; return (f x1) },我们可以将do脱糖成liftM f m1 = m1 &gt;&gt;= return . f。我们可以将(&gt;&gt;=) 翻转为liftM f m1 = return . f =&lt;&lt; m1 并省略m1 以得到liftM f = (return . f =&lt;&lt;) 一点无点魔法,我们得到liftM = (=&lt;&lt;) . (.) return

    【讨论】:

    • 您能否添加您如何从const . purefmap pure . const?顺便说一句,从(.) 开始可能比写fmap 更容易(然后解释(弄清楚?)它属于什么Functor 实例)。
    • @Bergi 其实你是对的,越早做越简单。
    【解决方案2】:

    另一个答案最终会到达那里,但它需要一个漫长的路线。真正需要的只是liftMconst 的定义和一个单子定律:m1 &gt;&gt; m2m1 &gt;&gt;= \_ -&gt; m2 必须在语义上相同。 (确实,这是(&gt;&gt;)的默认实现,很少被覆盖。)然后:

    liftM (const x) y
    = { definition of liftM* }
    y >>= \z -> pure (const x z)
    = { definition of const }
    y >>= \z -> pure x
    = { monad law }
    y >> pure x
    

    * 好的,好的,所以liftM 的实际定义使用return 而不是pure。随便。

    【讨论】:

    • 有趣。出于某种原因,我认为标准定义是liftM = fmap,具有更严格的类型。有了上面的真实定义,想要得到的方程就简单多了:)
    • @chi 即使没有它也不错:fmap f m = m &gt;&gt;= return . f 也是一个单子定律(经常被遗忘的定律之一)。
    • 该定律本身遵循参数化和单子定律m &gt;&gt;= pure = m
    【解决方案3】:

    另一种可能的途径,利用适用法则:

    例如我发现y &gt;&gt; pure x可以改写如下[...]

    fmap (const id) y <*> pure x
    

    这相当于……

    fmap (const id) y <*> pure x
    pure ($ x) <*> fmap (const id) y -- interchange law of applicatives
    fmap ($ x) (fmap (const id) y) -- fmap in terms of <*>
    fmap (($ x) . const id) y -- composition law of functors
    fmap (const x) y
    

    ...正如您所指出的,它与liftM (const x) y 相同。

    这条路线只需要应用法则而不是单子法则反映了(*&gt;)(&gt;&gt;) 的另一个名称)是一个Applicative 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-06
      • 1970-01-01
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-02
      相关资源
      最近更新 更多