So the type signature of ap
is Monad m => m (a -> b) -> m a -> m b
. You've given it zip
and tail
as arguments, so let's look at their type signatures.
Starting with tail :: [a] -> [a] ~ (->) [a] [a]
(here ~
is the equality operator for types), if we compare this type against the type of the second argument for ap
,
(->) [x] [x] ~ m a
((->) [x]) [x] ~ m a
we get a ~ [x]
and m ~ ((->) [x]) ~ ((->) a)
. Already we can see that the monad we're in is (->) [x]
, not []
. If we substitute what we can into the type signature of ap
we get:
(((->) [x]) ([x] -> b)) -> (((->) [x]) [x]) -> (((->) [x]) b)
Since this is not very readable, it can more normally be written as
([x] -> ([x] -> b)) -> ([x] -> [x]) -> ([x] -> b)
~ ([x] -> [x] -> b ) -> ([x] -> [x]) -> ([x] -> b)
The type of zip
is [x] -> [y] -> [(x, y)]
. We can already see that this lines up with the first argument to ap
where
[x] ~ [x]
[y] ~ [x]
[(x, y)] ~ b
Here I've listed the types vertically so that you can easily see which types line up. So obviously x ~ x
, y ~ x
, and [(x, y)] ~ [(x, x)] ~ b
, so we can finish substituting b ~ [(x, x)]
into ap
's type signature and get
([x] -> [x] -> [(x, x)]) -> ([x] -> [x]) -> ([x] -> [(x, x)])
-- zip tail ( ap zip tail )
-- ap zip tail u = zip u (tail u)
I hope that clears things up for you.
EDIT: As danvari pointed out in the comments, the monad (->) a
is sometimes called the reader monad.