是`x >>纯y`相当于`liftM(const y)x`

问题描述 投票:15回答:3

这两个表达方式

y >> pure x
liftM (const x) y

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

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

flip (>>) . pure
liftM . const

请注意,这两个函数都具有Monad m => a -> m b -> m a类型。

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

例如,我发现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
3个回答
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。随你。


12
投票

Yes they are the same

让我们从flip (>>) . pure开始,这是你提供的x >> pure y的免费版本:

flip (>>) . pure

这是flip (>>)只是(=<<) . const的情况所以我们可以改写为:

((=<<) . const) . pure

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

(=<<) . (const . pure)

现在我们想重写const . pure。我们可以注意到const只是pure上的(a ->),这意味着因为pure . purefmap pure . pure,所以const . pure(.) pure . const,((.)fmap(a ->))。

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

现在我们再次联系:

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

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

liftM . const

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


1:liftM的定义是liftM f m1 = do { x1 <- m1; return (f x1) },我们可以将do变成liftM f m1 = m1 >>= return . f。我们可以翻转(>>=)liftM f m1 = return . f =<< m1和elide the m1liftM f = (return . f =<<)有点无点魔术我们得到liftM = (=<<) . (.) return


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相同。

这条路线只需要适用法律,而不是monad那些反映了(*>)(>>)的另一个名字)是Applicative方法。

© www.soinside.com 2019 - 2024. All rights reserved.