假设有一个操作(??)
,使得
(a ?? b) ?? c = a ?? (b ?? c)
也就是说,(??)
是可结合的
必须满足这种情况吗?
liftA2 (??) (liftA2 (??) a b) c = liftA2 (??) a (liftA2 (??) b c)
也就是说,liftA2 (??)
是可结合的。
如果我们愿意的话,可以将其重写为:
fmap (??) (fmap (??) a <*> b) <*> c = fmap (??) a <*> (fmap (??) b <*> c)
我花了一点时间研究应用定律,但我无法证明这是正确的。所以我开始尝试反驳它。我尝试过所有开箱即用的应用(Maybe
、[]
、Either
等),都遵循这个定律,所以我想我会创建自己的。
我最好的想法是创建一个带有额外信息的空应用。
data Vacuous a = Vac Alg
其中Alg
是我稍后会自行定义的某种代数,以使属性失败但适用法则成功。
现在我们将实例定义为:
instance Functor Vacuous where
fmap f = id
instance Applicative Vacuous where
pure x = Vac i
liftA2 f (Vac a) (Vac b) = Vac (comb a b)
(Vac a) <*> (Vac b) = Vac (comb a b)
在这里,i
是待确定的 Alg 元素,comb
是待确定的 Alg 二元组合器。实际上,我们没有其他方式来定义它。
如果我们想要满足 恒等律,那么 i
就必须是在 comb
上的一个恒等元素。这时我们就可以免费得到 同态 和 交换。但是此时,由于 组成 要求 comb
在 Alg
上具有结合性。
((pure (.) <*> Vac u) <*> Vac v) <*> Vac w = Vac u <*> (Vac v <*> Vac w)
((Vac i <*> Vac u) <*> Vac v) <*> Vac w = Vac u <*> (Vac v <*> Vac w)
(Vac u <*> Vac v) <*> Vac w = Vac u <*> (Vac v <*> Vac w)
(Vac (comb u v)) <*> Vac w = Vac u <*> (Vac (comb v w))
Vac (comb (comb u v) w) = Vac (comb u (comb v w))
comb (comb u v) w = comb u (comb v w)
强制我们满足该属性。
有反例吗?如果没有,我们如何证明这个属性?
base
的instance (Applicative f, Semigroup a) => Semigroup (Ap f a)
依赖于此属性为真。 - Joseph Sible-Reinstate Monica