Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do Haskell type signature declarations have multiple arrows?

Tags:

Sorry this is worded poorly, but it's hard to describe.

I guess I'll just jump to the example:

add                     :: Integer -> Integer -> Integer
add x y                 =  x + y

why is it:

:: Integer -> Integer -> Integer

instead of:

:: Integer, Integer -> Integer

the arrow is the "Function type-mapping operator", not some kind of separator, no?

like image 498
Bret Fontecchio Avatar asked Dec 08 '13 22:12

Bret Fontecchio


People also ask

What does -> mean in Haskell?

(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.

What is Haskell type signature?

From HaskellWiki. A type signature is a line like. inc :: Num a => a -> a. that tells, what is the type of a variable. In the example inc is the variable, Num a => is the context and a -> a is its type, namely a function type with the kind * -> * .


1 Answers

Because of currying. Think about the type of this:

add 3 :: Integer -> Integer

If you give add one number it returns a function that maps an Integer to another integer. So you could do this:

map (add 3) [1..10]

It doesn't make sense to treat arguments differently from return types with partial application.

EDIT to clarify

I think bheklilr makes a good point that the type signature can be read like this

add :: Integer -> (Integer -> Integer)

We can take a function with more arguments, zipWith3 because it is the only one I can really think of.

zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]

If we just read what this does it takes a function that takes 3 values and returns a fourth and then 3 lists of those values respectively and it returns a list of the fourth value. Trying it out.

add3 :: Int -> Int -> Int -> Int
add3 a b c = a + b + c

Prelude>zipWith3 add3 [1] [2] [3]
[6]

Although, in this case all the values are of type Int it still demonstrates the point.

Now what if we don't give it all the lists? What if we give it no lists just add3.

zipWith3 add3 :: [Int] -> [Int] -> [Int] -> [Int]
zipWith3 add3 :: [Int] -> ([Int] -> [Int] -> [Int])
zipWith3 add3 :: [Int] -> [Int] -> ([Int] -> [Int])

So, now we have a function that takes 3 lists and returns a list. But this is also a function that takes a list are returns a function that takes 2 lists and returns a list. There is no way to distinguish between them really.

(zipWith3 add3) [1,2] [3,4] [5,6] :: [Int]
(zipWith3 add3) [1,2] :: [Int] -> [Int] -> [Int]

See where I'm going with this? There is no distinction between arguments are return types.

like image 61
DiegoNolan Avatar answered Sep 21 '22 15:09

DiegoNolan