Thank you, Willem Van Onsem for the great answer.
Let's understand zipWith id
from the eyes of the type inference system of ghc.
first, consider the type of zipWith
Prelude> :info zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
-- Defined in ‘GHC.List’
First argument of zipWith
is a function which accepts a function which takes two arguments.
(a -> b -> c)
can also be re-written as a -> (b -> c)
now consider zipWith id
. type of id
is from a -> a
we have put id
in a place where a two argument function must go.
So, type inference would make (a -> b -> c)
look like a -> (b -> c)
(notice a -> (b -> c)
takes one arument a and gives b -> c
i.e a single argument function.)
But, making a -> (b -> c)
an identity function would be possible only if a
is (b -> c).
When a
is (b -> c) the function a -> b -> c
becomes ((b -> c) -> (b -> c))
So, type inferencing system would infer a
as (b -> c)
and the resultant output would be [a] -> [b] -> [c]
replacing a
with b -> c
.
Replace a
with (b -> c).
Make (a -> b -> c) look like id
. (a -> b -> c) can be made to look like id
by the above replacement.
((b -> c) -> b -> c) which can also be written as ((b -> c) -> (b -> c)) which is id :: x -> x
where x
is (b -> c)
zipWith :: ((b -> c) -> b -> c) -> [b -> c] -> [b] -> [c]
So finally we get output as [b -> c] -> [b] -> [c]