I wondered how to write f x = zip x (tail x)
in point free. So I used the pointfree program and the result was f = ap zip tail
. ap
being a function from Control.Monad
I do not understand how the point free definition works. I hope I can figure it out if I can comprehend it from the perspective of types.
import Control.Monad (ap)
let f = ap zip tail
let g = ap zip
:info ap zip tail f g
ap :: Monad m => m (a -> b) -> m a -> m b
-- Defined in `Control.Monad'
zip :: [a] -> [b] -> [(a, b)] -- Defined in `GHC.List'
tail :: [a] -> [a] -- Defined in `GHC.List'
f :: [b] -> [(b, b)] -- Defined at <interactive>:3:5
g :: ([a] -> [b]) -> [a] -> [(a, b)]
-- Defined at <interactive>:4:5
By looking at the expression ap zip tail
I would think that zip is the first parameter of ap
and tail is the second parameter of ap
.
Monad m => m (a -> b) -> m a -> m b
\--------/ \---/
zip tail
But this is not possible, because the types of zip
and tail
are completely different than what the function ap
requires. Even with taking into consideration that the list is a monad of sorts.
There are two aspects to understanding this:
Firstly, this helped me understand the type magic:
In this case, for
<*>
,Note that in 5,
f
is a type constructor. Applyingf
tox
produces a type. Also, here=
is overloaded to mean equivalence of types.y
is currently a place-holder, in this case, it is[a]
, which meansUsing 6, we can rewrite 1,2 and 3 as follows:
So, looking at 4, we are substituting as follows:
(Repetition of 6 here again as 12 )
Secondly, the information flow, i.e. the actual functionality. This is easier, it is clear from the definition of
<*>
for the Applicative instance ofy →
, which is rewritten here with different identifier names and using infix style:Substituting as follows:
Gives:
So the type signature of
ap
isMonad m => m (a -> b) -> m a -> m b
. You've given itzip
andtail
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 forap
,we get
a ~ [x]
andm ~ ((->) [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 ofap
we get:Since this is not very readable, it can more normally be written as
The type of
zip
is[x] -> [y] -> [(x, y)]
. We can already see that this lines up with the first argument toap
whereHere 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 substitutingb ~ [(x, x)]
intoap
's type signature and getI hope that clears things up for you.
EDIT: As danvari pointed out in the comments, the monad
(->) a
is sometimes called the reader monad.