Understanding Haskell Type Signatures

CaitlinG picture CaitlinG · Mar 11, 2014 · Viewed 10.7k times · Source

I am in the process of teaching myself Haskell and I was wondering about the following type signatures:

Prelude> :t ($)
($) :: (a -> b) -> a -> b
Prelude>

How should I interpret (no pun intended) that?

A semi-similar result is also proving to be puzzling:

Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude>

Answer

bheklilr picture bheklilr · Mar 11, 2014

I'll start with map. The map function applies an operation to every element in a list. If I had

add3 :: Int -> Int
add3 x = x + 3

Then I could apply this to a whole list of Ints using map:

> map add3 [1, 2, 3, 4]
[4, 5, 6, 7]

So if you look at the type signature

map :: (a -> b) -> [a] -> [b]

You'll see that the first argument is (a -> b), which is just a function that takes an a and returns a b. The second argument is [a], which is a list of values of type a, and the return type [b], a list of values of type b. So in plain english, the map function applies a function to each element in a list of values, then returns the those values as a list.

This is what makes map a higher order function, it takes a function as an argument and does stuff with it. Another way to look at map is to add some parentheses to the type signature to make it

map :: (a -> b) -> ([a] -> [b])

So you can also think of it as a function that transforms a function from a to b into a function from [a] to [b].


The function ($) has the type

($) :: (a -> b) -> a -> b

And is used like

> add3 $ 1 + 1
5

All it does is take what's to the right, in this case 1 + 1, and passes it to the function on the left, here add3. Why is this important? It has a handy fixity, or operator precedence, that makes it equivalent to

> add3 (1 + 1)

So whatever to the right gets essentially wrapped in parentheses before being passed to the left. This just makes it useful for chaining several functions together:

> add3 $ add3 $ add3 $ add3 $ 1 + 1

is nicer than

> add3 (add3 (add3 (add3 (1 + 1))))

because you don't have to close parentheses.