Skip to content

Currying: From Two Arguments to a Pair and Back

Multi-argument functions that are expressed as single-argument functions that themselves return functions are sometimes called "curried functions", named (just as the language Haskell itself) after the logicial Haskell Curry.

Sometimes, we do want functions that take a pair of values as arguments though. Let's play with a little example using our old friend, the map function:

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

Remember, this function takes as its first argument a function f that takes a value of type a as argument and returns a value of type b. The second argument of map is a list of values of type a—that's the type [a]. It produces a list of values of type [b] where each value in this list is obtained by applying f to the corresponding element in the input list. For example,

GHCi
>>> map (2 *) [1,2,3]
[2,4,6]

Oh yes, we can partially apply operators as well. Here, we provide the first argument of the multiplication but not the second, so (2 *) is a function that multiplies its argument by 2.

Now what if I gave you a list of pairs, say [(1,3), (4,9), (3,7)], and I wanted to produce from it the list [3,36,21], that is, each entry in the result list is the product of the two numbers in the corresponding pair in the input list: 3 = 1 * 3, 36 = 4 * 9, 21 = 3 * 7? Ideally, we would like to use map multiply [(1,3), (4,9), (3,7)] to do this, but his doesn't quite work. The first argument of multiply needs to be of type Int. Each entry in the list [(1,3), (4,9), (3,7)] is a pair of type (Int, Int). So the argument types don't match. Even if they did, multiply takes two arguments. By applying it to only one argument (of type (Int, Int)), we'd obtain as a result a function, not a value. What we need is not a function of type Int -> Int -> Int, the type of multiply, but a function of type (Int, Int) -> Int.

We could easily build such a function, and one that behaves exactly like multiply using a lambda expression:

GHCi
>>> multiply x y = x * y
>>> map (\(x, y) -> multiply x y) [(1,3), (4,9), (3,7)]
[3,36,21]

or more directly,

GHCi
>>> map (\(x, y) -> x * y) [(1,3), (4,9), (3,7)]
[3,36,21]

However, it is common enough that we want to turn a two-argument function into one that takes a pair as argument and vice versa that the Haskell standard library provides us with two functions to do this. Given that Haskell-style multi-argument functions are called curried functions, the function to turn a function of type (a, b) -> c into a function of type a -> b -> c is called curry, and the one that turns a function of type a -> b -> c into a function of type (a, b) -> c, being its inverse, is called uncurry. If they didn't exist already, here is how we could define them (and how they are defined in the standard library):

curry :: ((a, b) -> c) -> (a -> b -> c)
curry f a b = f (a, b)

uncurry :: (a -> b -> c) -> ((a, b) -> c)
uncurry f (a, b) = f a b

In our example of computing a list of products from a list of pairs, we need uncurry:

GHCi
>>> multiply x y = x * y
>>> map (uncurry multiply) [(1,3), (4,9), (3,7)]
[3,36,21]

Exercise

The solution to multiplying pairs of numbers in a list we have just developed is a bit silly. We define a two-argument function multiply only to uncurry it and pass it as an argument to map. Surely, this is much more succinct (because it avoids defining a separate function multiply) and achieves the same:

GHCi
>>> map (\(x, y) -> x * y) [(1,3), (4,9), (3,7)]
[3,36,21]

You can actually arrive at this solution via basic substitution. We have

multiply = \x y -> x * y`

Thus,

uncurry multiply = \(x, y) -> multiply x y         -- Definition of uncurry
                 = \(x, y) -> (\x y -> x * y) x y  -- Substitution of multiply with its definition
                 = \(x, y) -> x * y                -- Substitution of function application with its body

Even the definition of the anonymous function \(x, y) -> x * y feels too verbose. Can you given an expression that multiplies the pairs in a list of pairs of numbers that neither defines a new function nor uses an anonymous function as the first argument to map? To make this precise, you are expected to come up with an expression map (...) [(1,3), (4,9), (3,7)] such that

GHCi
>>> map (...) [(1,3), (4,9), (3,7)]
[3,36,21]

and the ... is not a lambda expression nor does it use any helper function you have defined, such as multiply.

Solution
GHCi
>>> map (uncurry (*)) [(1,3), (4,9), (3,7)]
[3,36,21]

Recall that arithmetic operators in Haskell are essentially functions like any other, only they are normally used in infix notation, since they are composed of special characters. We also discussed that we can use these operators in prefix notation by enclosing them in parentheses:

GHCi
>>> (*) 3 4
12

So, (*) is a two-argument function that returns the product of its arguments. uncurry (*) turns this into a function that takes a single argument, a pair, and returns the product of the two components of this pair. That's exactly what we need here.