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