So, I wanted to manually prove the Composition law for Maybe applicative which is:
u <*> (v <*> w) = pure (.) <*> u <*> v <*> w
You translated the use of (<*>)
through fmap
. The other answers also do some pattern matching.
Usually you need to open the definition of the functions to reason about them, not just assume what they do. (You assume (pure f) <*> x
is the same as fmap f x
)
For example, (<*>)
is defined as ap
for Maybe
in Control.Applicative
(or can be proven to be equivalent to it for any Monad
, even if you redefine it), and ap
is borrowed from Monad
, which is defined as liftM2 id
, and liftM2
is defined like so:
liftM2 f m1 m2 = do
x <- m1
y <- m2
return $ f x y
So, reduce both left- and right-hand sides to see they are equivalent:
u <*> (v <*> w) = liftM2 id u (liftM2 id v w)
= do
u1 <- u
v1 <- do
v1 <- v
w1 <- w
return $ id v1 w1
return $ id u1 v1
= do
u1 <- u
v1 <- do
v1 <- v
w1 <- w
return $ v1 w1
return $ u1 v1
-- associativity law: (see [1])
= do
u1 <- u
v1 <- v
w1 <- w
x <- return $ v1 w1
return $ u1 x
-- right identity: x' <- return x; f x' == f x
= do
u1 <- u
v1 <- v
w1 <- w
return $ u1 $ v1 w1
Now, the right-hand side:
pure (.) <*> u <*> v <*> w
= liftM2 id (liftM2 id (liftM2 id (pure (.)) u) v) w
= do
g <- do
f <- do
p <- pure (.)
u1 <- u
return $ id p u1
v1 <- v
return $ id f v1
w1 <- w
return $ id g w1
= do
g <- do
f <- do
p <- return (.)
u1 <- u
return $ p u1
v1 <- v
return $ f v1
w1 <- w
return $ g w1
-- associativity law:
= do
p <- return (.)
u1 <- u
f <- return $ p u1
v1 <- v
g <- return $ f v1
w1 <- w
return $ g w1
-- right identity: x' <- return x; f x' == f x
= do
u1 <- u
v1 <- v
w1 <- w
return $ ((.) u1 v1) w1
-- (f . g) x == f (g x)
= do
u1 <- u
v1 <- v
w1 <- w
return $ u1 $ v1 w1
That's it.
[1] http://www.haskell.org/haskellwiki/Monad_laws