x >>纯y是否等同于liftM(const y)x

时间:2019-03-27 18:31:10

标签: haskell monads functor applicative

两个表达式

y >> pure x
liftM (const x) y

在Haskell中具有相同的类型签名。 我很好奇它们是否相等,但我既不能提供事实证明,也不能提供反例。

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

flip (>>) . pure
liftM . const

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

我使用Haskell为单子,应用程序和函子给出的定律将这两个陈述转换为各种等效形式,但是我无法在两者之间产生一系列等效关系。

例如,我发现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

这些都不是必然的,但我无法想到在任何情况下都不等同。

3 个答案:

答案 0 :(得分:15)

另一个答案最终到达了那儿,但它走了一条漫长的路。实际需要的只是liftMconst的定义和一个monad定律:m1 >> m2m1 >>= \_ -> m2在语义上必须相同。 (实际上,这是(>>)的默认实现,很少会覆盖它。)然后:

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。随便。

答案 1 :(得分:12)

是的,它们是相同的

让我们从flip (>>) . pure开始,它是您提供的x >> pure y的无意义版本:

flip (>>) . pure

flip (>>)只是(=<<) . const就是这种情况,因此我们可以将其重写为:

((=<<) . const) . pure

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

(=<<) . (const . pure)

现在,我们想重写const . pure。我们可以注意到const只是pure上的(a ->),这意味着由于pure . purefmap pure . pureconst . pure(.) pure . const, (对于函子(.),{fmap(a ->))。

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

现在,我们再次关联:

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

((=<<) . (.) pure)liftM 1 的定义,因此我们可以替代:

liftM . const

这就是目标。两者是相同的。


1:liftM的定义为liftM f m1 = do { x1 <- m1; return (f x1) },我们可以将do糖化为liftM f m1 = m1 >>= return . f。我们可以将(>>=)的{​​{1}}翻转并滑出liftM f m1 = return . f =<< m1以获得m1一点点无用的魔法,我们得到liftM f = (return . f =<<)

答案 2 :(得分:4)

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

  

例如,我发现y >> 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相同。

此路线仅需要适用法律,而不是单子法律,这反映了(*>)(>>)的另一个名称)是一种Applicative方法的情况。