两个表达式
y >> pure x
liftM (const x) y
在Haskell中具有相同的类型签名。 我很好奇它们是否相等,但我既不能提供事实证明,也不能提供反例。
如果我们重写两个表达式以便可以消除x
和y
,那么问题就变成了以下两个函数是否等效
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
这些都不是必然的,但我无法想到在任何情况下都不等同。
答案 0 :(得分:15)
另一个答案最终到达了那儿,但它走了一条漫长的路。实际需要的只是liftM
,const
的定义和一个monad定律:m1 >> m2
和m1 >>= \_ -> 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 . pure
是fmap pure . pure
,const . 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
方法的情况。