3
votes

I have a question regarding the type signatures in Haskell, which I find sometimes a bit difficult to unterstand. For example the type signature of zipWith is:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

What I see here is that zipWith expects a function (with parameters of type a and b), a list with as, a list with bs and it gives us a list of cs. But I do not unterstand why I can use zipWith with (+) for example, which has the signature:

(+) :: a -> a -> a

From my point of view the signature of (+) doesn't match with the signature of (a -> b -> c). (+) only expects parameters of type a, while (a -> b -> c) expects parameters of different types: a and b. Can anyone give me a hint what is my fault?

1
Another way to look at the zipWith function is that it "lifts" a function of two arguments to the list monad since the signature could be written as zipWith :: (a -> b -> c) -> ([a] -> [b] -> [c]). In the case of (+) :: Int -> Int -> Int, a ~ Int, b ~ Int, and c ~ Int, so zipWith (+) :: [Int] -> [Int] -> [Int].bheklilr

1 Answers

4
votes

(a -> b -> c) means any function that takes a type a and a type b and returns a type c. There is nothing to stop you from using a function that has the signature (a -> a -> a), it just happens that in this case the types are all the same.

Assume you had a method with this signature:

zipWith' :: (a -> a -> a) -> [a] -> [a] -> [a]

you couldn't use a method with a signature of (a -> b -> c) in this case as the expected method signature is more restrictive.