A previous question discussed how the type of Haskell expression ap zip tail
can be translated into the type of \x -> zip x (tail x)
. It was enlightening, but neither the question nor answer there dealt with why the former expression gives the same results as the latter expression, only that their types are equivalent. For all I know it could've meant \x -> zip x (tail (tail x))
instead.
I tried reading the documentation for ap but got nowhere. How does one read ap
to get the understanding that ap zip tail
gives the same results as \x -> zip x (tail x)
?
First, look at the source as well:
ap m1 m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }
-- Since many Applicative instances define (<*>) = ap, we
-- cannot define ap = (<*>)
You know (from the previous question) that the monad we are interested in is (->) [a]
. Since we know from that comment that ap
is the same as (<*>)
, next we look at
instance Applicative ((->) a) where
pure = const
(<*>) f g x = f x (g x)
(<*>) zip tail x = zip x (tail x)
and we can move x
to the right and get zip <*> tail = \x -> zip x (tail x)
.
You could also use the definition of ap
and instance Monad (->) a
directly without looking at <*>
, but this would take a bit more effort.
For all I know it could've meant \x -> zip x (tail (tail x)) instead.
This is actually impossible just from the type: m (a -> b) -> m a -> m b
is (c -> (a -> b)) -> (c -> a) -> (c -> b)
in this monad, so ap f1 f2
can't apply f2
twice: it has type c -> a
and f2 (f2 <anything>)
wouldn't typecheck.
The second part of this answer explains it. Remember that <*>
is the same as ap
, but just as an infix operator, and as part of Applicative
rather than it's subclass, Monad
, since only Applicative
is needed for it to work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With