Every function in Haskell officially only takes one parameter

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com, or follow me on Twitter.

The purity of Haskell is, of course, very interesting:

Every function in Haskell officially only takes one parameter. So how is it possible that we defined and used several functions that take more than one parameter so far? Well, it’s a clever trick! All the functions that accepted several parameters so far have been curried functions. What does that mean? You’ll understand it best on an example. Let’s take our good friend, the max function. It looks like it takes two parameters and returns the one that’s bigger. Doing max 4 5 first creates a function that takes a parameter and returns either 4 or that parameter, depending on which is bigger. Then, 5 is applied to that function and that function produces our desired result. That sounds like a mouthful but it’s actually a really cool concept. The following two calls are equivalent:

ghci> max 4 5
5

ghci> (max 4) 5
5

Putting a space between two things is simply function application. The space is sort of like an operator and it has the highest precedence. Let’s examine the type of max. It’s max :: (Ord a) => a -> a -> a. That can also be written as max :: (Ord a) => a -> (a -> a). That could be read as: max takes an a and returns (that’s the ->) a function that takes an a and returns an a. That’s why the return type and the parameters of functions are all simply separated with arrows.

So how is that beneficial to us? Simply speaking, if we call a function with too few parameters, we get back a partially applied function, meaning a function that takes as many parameters as we left out. Using partial application (calling functions with too few parameters, if you will) is a neat way to create functions on the fly so we can pass them to another function or to seed them with some data.

Take a look at this offensively simple function:

multThree :: (Num a) => a -> a -> a -> a
multThree x y z = x * y * z

What really happens when we do multThree 3 5 9 or ((multThree 3) 5) 9? First, 3 is applied to multThree, because they’re separated by a space. That creates a function that takes one parameter and returns a function. So then 5 is applied to that, which creates a function that will take a parameter and multiply it by 15. 9 is applied to that function and the result is 135 or something. Remember that this function’s type could also be written as multThree :: (Num a) => a -> (a -> (a -> a)). The thing before the -> is the parameter that a function takes and the thing after it is what it returns. So our function takes an a and returns a function of type (Num a) => a -> (a -> a). Similarly, this function takes an a and returns a function of type (Num a) => a -> a. And this function, finally, just takes an a and returns an a. Take a look at this:

ghci> let multTwoWithNine = multThree 9

ghci> multTwoWithNine 2 3
54

ghci> let multWithEighteen = multTwoWithNine 2

ghci> multWithEighteen 10
180

By calling functions with too few parameters, so to speak, we’re creating new functions on the fly. What if we wanted to create a function that takes a number and compares it to 100? We could do something like this:

compareWithHundred :: (Num a, Ord a) => a -> Ordering
compareWithHundred x = compare 100 x

If we call it with 99, it returns a GT. Simple stuff.

Source