I am playing a bit with zipWith
and encounter following:
Prelude Control.Applicative> :t zipWith id
zipWith id :: [b -> c] -> [b] -> [c]
Why does the compiler expect for the next argument a list of functions?
I tried to analyze, but could not conclude, why the next argument must be a list of functions.
How did the signature is getting apply, when I pass id
to zipWith
?
The type of zipWith
is:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
And the type of id
is:
id :: d -> d
So if we now want to derive the type of zipWith id
, we push the type of id :: d -> d
into the type of the first argument of zipWith
:
d -> d
~ a -> (b -> c)
So that means that: a ~ d
and a ~ b -> c
. So that means that the type of zipWith id
is now:
zipWith id :: [a] -> [b] -> [c]
-> zipWith id :: [b -> c] -> [b] -> [c]
How does this work: the first list has to contain a list of functions f :: b -> c
, and the second list, a list of elements x :: b
, and it thus calculates a list of elements f x :: c
.
For example:
Prelude> zipWith id [(+1),(5/),(3*),(3-)] [1,4,2,5]
[2.0,1.25,6.0,-2.0]
since 1+1
is 2.0
, 5/4
is 1.25
, 3*2
is 6.0
and 3-5
is -2.0
.
So zipWith id
will take two elements f
and x
, and apply id f x
on these, or more verbose (id f) x
. Since id f
is f
, it will thus calculate f x
.
We can thus conclude that zipWith
is an elementwise mapping.
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