Ответ 1
Да, похоже, это законный Applicative
. Weird!
Как @JosephSible указует, вы можете считывать идентификационный, гомоморфизм и переставить законы непосредственно из определений. Единственный хитрый - это закон композиции.
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
Есть восемь случаев, чтобы проверить, так что пристегните.
- Один случай с тремя
Return
s:pure (.) <*> Return f <*> Return g <*> Return z
- Тривиально следует из ассоциативности
(.)
.
- Тривиально следует из ассоциативности
- Три случая с одним
Free
:-
pure (.) <*> Free u <*> Return g <*> Return z
- Работая в обратном направлении от
Free u <*> (Return g <*> Return z)
вы получаетеfmap (\f → f (gz)) (Free u)
, так что это следует из закона функторов.
- Работая в обратном направлении от
-
pure (.) <*> Return f <*> Free v <*> Return z fmap ($z) $ fmap f (Free v) fmap (\g -> f (g z)) (Free v) -- functor law fmap (f . ($z)) (Free v) fmap f (fmap ($z) (Free v)) -- functor law Return f <$> (Free v <*> Return z) -- RHS of '<*>' (first and second cases) QED
-
pure (.) <*> Return f <*> Return g <*> Free w
- Немедленно сводится к
fmap (f. g) (Free w)
, что следует из закона функторов.
- Немедленно сводится к
-
- Три случая с одним
Return
:-
pure (.) <*> Return f <*> Free v <*> Free w Free $ fmap (<*>) (fmap (fmap (f.)) v) <*> w Free $ fmap (\y z -> fmap (f.) y <*> z) v <*> w -- functor law Free $ fmap (\y z -> fmap (.) <*> Return f <*> y <*> z) v <*> w -- definition of fmap, twice Free $ fmap (\y z -> Return f <*> (y <*> z)) v <*> w -- composition Free $ fmap (\y z -> fmap f (y <*> z)) v <*> w -- RHS of fmap, definition of liftA2 Free $ fmap (fmap f) $ fmap (<*>) v <*> w -- functor law, eta reduce fmap f $ Free $ liftA2 (<*>) v w -- RHS of fmap Return f <*> Free v <*> Free w -- RHS of <*> QED.
-
pure (.) <*> Free u <*> Return g <*> Free w Free ((fmap (fmap ($g))) (fmap (fmap (.)) u)) <*> Free w Free (fmap (fmap (\f -> f . g) u)) <*> Free w -- functor law, twice Free $ fmap (<*>) (fmap (fmap (\f -> f . g)) u) <*> w Free $ fmap (\x z -> fmap (\f -> f . g) x <*> z) u <*> w -- functor law Free $ fmap (\x z -> pure (.) <*> x <*> Return g <*> z) u <*> w Free $ fmap (\x z -> x <*> (Return g <*> z)) u <*> w -- composition Free $ fmap (<*>) u <*> fmap (Return g <*>) w -- https://gist.github.com/benjamin-hodgson/5b36259986055d32adea56d0a7fa688f Free u <*> fmap g w -- RHS of <*> and fmap Free u <*> (Return g <*> w) QED.
-
pure (.) <*> Free u <*> Free v <*> Return z Free (fmap (<*>) (fmap (fmap (.)) u) <*> v) <*> Return z Free (fmap (\x y -> fmap (.) x <*> y) u <*> v) <*> Return z -- functor law Free $ fmap (fmap ($z)) (fmap (\x y -> fmap (.) x <*> y) u <*> v) Free $ liftA2 (\x y -> (fmap ($z)) (fmap (.) x <*> y)) u v -- see Lemma, with f = fmap ($z) and g x y = fmap (.) x <*> y Free $ liftA2 (\x y -> fmap (.) x <*> y <*> Return z) u v -- interchange Free $ liftA2 (\x y -> x <*> (y <*> Return z)) u v -- composition Free $ liftA2 (\f g -> f <*> fmap ($z) g) u v -- interchange Free $ fmap (<*>) u <*> (fmap (fmap ($z)) v) -- https://gist.github.com/benjamin-hodgson/5b36259986055d32adea56d0a7fa688f Free u <*> Free (fmap (fmap ($z)) v) Free u <*> (Free v <*> Return z) QED.
-
- Три
Free
s:pure (.) <*> Free u <*> Free v <*> Free w
- В этом случае используется только случай
Free
/Free
для<*>
, правая часть которого совпадает с правой частьюCompose
<*>
. Так что это следует из правильности экземпляраCompose
.
- В этом случае используется только случай
Для pure (.) <*> Free u <*> Free v <*> Return z
я использовал лемму:
Лемма: fmap f (fmap gu <*> v) = liftA2 (\xy → f (gxy)) uv
.
fmap f (fmap g u <*> v)
pure (.) <*> pure f <*> fmap g u <*> v -- composition
fmap (f .) (fmap g u) <*> v -- homomorphism
fmap ((f .) . g) u <*> v -- functor law
liftA2 (\x y -> f (g x y)) u v -- eta expand
QED.
По-разному я использую функторные и аппликативные законы в предположении индукции.
Это было довольно весело доказать! Я хотел бы видеть формальное доказательство в Coq или Agda (хотя я подозреваю, что проверка завершения/положительности может испортить это).