Exercise solution: liftA3, liftA4
It’s handy that Applicative
gives us the choice between liftA2
and (<*>)
, and since the two functions are so closely related, it’s straightforward for the compiler to be able to derive one from the other. We saw how liftA2
is like an fmap
for functions with two arguments instead of one.
fmap :: Functor f => (a -> b) -> f a -> f b
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
The only reasonable thing to do, when confronted with this information, is ask oneself: why not liftA3
then? Or liftA4
?
liftA3
, at least, is something that exists in the Control.Applicative
module of base
(though, like liftA2
, it’s not in Prelude
). Try implementing it for yourself – no peeking at the source code! If you feel especially ambitious, try implementing a liftA4
as well, which is not in base
but that need not stop us from chasing our dreams. Use what you know about fmap
and the relationship of liftA2
to (<*>)
to help you.