4

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) ?

  • in case you wonder how you can find out yourself: first seach it: https://www.haskell.org/hoogle/?hoogle=ap you see that you most likely use the monad instance so look at `Monad`: https://hackage.haskell.org/package/base-4.8.0.0/docs/Control-Monad.html#t:Monad and see if you can find the right instance below (it is `Monad ((->) r)` here) - there is hopefully a link to the source (https://hackage.haskell.org/package/base-4.8.0.0/docs/src/GHC-Base.html#line-621) and voila (also look at the source for `ap`: https://hackage.haskell.org/package/base-4.8.0.0/docs/src/GHC-Base.html#ap) – Random Dev Mar 31 '15 at 07:15

2 Answers2

7

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.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
1

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.

Community
  • 1
  • 1
algotrific
  • 323
  • 2
  • 9