So, I wanted to manually prove the Composition law for Maybe applicative which is:
u <*> (v <*> w) = pure (.) <*> u <*> v <*> w
Applicative functor expressions are just function applications in the context of some functor. Hence:
pure f <*> pure a <*> pure b <*> pure c
-- is the same as:
pure (f a b c)
We want to prove that:
pure (.) <*> u <*> v <*> w == u <*> (v <*> w)
Consider:
u = pure f
v = pure g
w = pure x
Therefore, the left hand side is:
pure (.) <*> u <*> v <*> w
pure (.) <*> pure f <*> pure g <*> pure x
pure ((.) f g x)
pure ((f . g) x)
pure (f (g x))
pure f <*> pure (g x)
pure f <*> (pure g <*> pure x)
u <*> (v <*> w)
For Maybe we know that pure = Just. Hence if u, v and w are Just values then we know that the composition law holds.
However, what if any one of them is Nothing? We know that:
Nothing <*> _ = Nothing
_ <*> Nothing = Nothing
Hence if any one of them is Nothing then the entire expression becomes Nothing (except in the second case if the first argument is undefined) and since Nothing == Nothing the law still holds.
Finally, what about undefined (a.k.a. bottom) values? We know that:
(Just f) <*> (Just x) = Just (f x)
Hence the following expressions will make the program halt:
(Just f) <*> undefined
undefined <*> (Just x)
undefined <*> Nothing
However the following expression will result in Nothing:
Nothing <*> undefined
In either case the composition law still holds.