在我研究Typoclassopedia期间,我遇到了这个证据,但我不确定我的证据是否正确。问题是:
有人可能会想到一种交换法的变体,它说的是将纯函数应用于有效的论证。使用上述法律,证明:
pure f <*> x = pure (flip ($)) <*> x <*> pure f
“上述法律”指向Applicative Laws的地方,简要说明:
pure id <*> v = v -- identity law
pure f <*> pure x = pure (f x) -- homomorphism
u <*> pure y = pure ($ y) <*> u -- interchange
u <*> (v <*> w) = pure (.) <*> u <*> v <*> w -- composition
我的证据如下:
pure f <*> x = pure (($) f) <*> x -- identical
pure f <*> x = pure ($) <*> pure f <*> x -- homomorphism
pure f <*> x = pure (flip ($)) <*> x <*> pure f -- flip arguments
答案 0 :(得分:3)
您的证明的前两个步骤看起来很好,但最后一步却没有。虽然flip
的定义允许您使用以下法律:
f a b = flip f b a
这并不意味着:
pure f <*> a <*> b = pure (flip f) <*> b <*> a
事实上,这一般是错误的。比较这两行的输出:
pure (+) <*> [1,2,3] <*> [4,5]
pure (flip (+)) <*> [4,5] <*> [1,2,3]
如果您需要提示,您需要在某些时候使用原始的交换法来证明这种变体。
事实上,我发现我必须使用同态,交换和组合定律来证明这一点,并且部分证明非常棘手,特别是使这些部分正确 - 就像($ f)
,这是不同的来自(($) f)
。让GHCi打开以仔细检查我的证明类型的每一步都检查并给出正确的结果是有帮助的。 (您上面的证据类型检查正常;只是最后一步没有合理性。)
> let f = sqrt
> let x = [1,4,9]
> pure f <*> x
[1.0,2.0,3.0]
> pure (flip ($)) <*> x <*> pure f
[1.0,2.0,3.0]
>
答案 1 :(得分:3)
我最终向后证明了这一点:
pure (flip ($)) <*> x <*> pure f
= (pure (flip ($)) <*> x) <*> pure f -- <*> is left-associative
= pure ($ f) <*> (pure (flip ($)) <*> x) -- interchange
= pure (.) <*> pure ($ f) <*> pure (flip ($)) <*> x -- composition
= pure (($ f) . (flip ($))) <*> x -- homomorphism
= pure (flip ($) f . flip ($)) <*> x -- identical
= pure f <*> x
最后一次转型的说明:
flip ($)
具有类型a -> (a -> c) -> c
,直观地说,它首先采用类型a
的参数,然后是接受该参数的函数,最后它使用第一个调用函数论点。所以flip ($) 5
将一个函数作为参数,它以5
作为参数调用。如果我们将(+ 2)
传递给flip ($) 5
,我们会得到flip ($) 5 (+2)
,它等同于表达式(+2) $ 5
,评估为7
。
flip ($) f
相当于\x -> x $ f
,这意味着它将一个函数作为输入,并以函数f
作为参数调用它。
这些函数的组成如下:首先flip ($)
取x
作为它的第一个参数,并返回一个函数flip ($) x
,这个函数正等待函数作为它的最后一个参数,将使用x
作为参数进行调用。现在,此函数flip ($) x
传递给flip ($) f
,或者将其写为等效的(\x -> x $ f) (flip ($) x)
,这会产生表达式(flip ($) x) f
,相当于f $ x
。
您可以检查flip ($) f . flip ($)
的类型是否类似(取决于您的函数f
):
λ: let f = sqrt
λ: :t (flip ($) f) . (flip ($))
(flip ($) f) . (flip ($)) :: Floating c => c -> c
答案 2 :(得分:1)
我注意到这样的定理通常在用 monoidal仿函数的数学风格编写时很少涉及,而不是应用版本,即具有等价的等级
class Functor f => Monoidal f where
pure :: a -> f a
(⑂) :: f a -> f b -> f (a,b)
然后法律
id <$> v = v
f <$> (g <$> v) = f . g <$> v
f <$> pure x = pure (f x)
x ⑂ pure y = fmap (,y) x
a⑂(b⑂c) = assoc <$> (a⑂b)⑂c
其中assoc ((x,y),z) = (x,(y,z))
。
该定理然后读取
pure u ⑂ x = swap <$> x ⑂ pure u
证明:
swap <$> x ⑂ pure u
= swap <$> fmap (,u) x
= swap . (,u) <$> x
= (u,) <$> x
= pure u ⑂ x
□