Currying and partial function application are important concepts in functional programming. However, for those new to functional programming it’s often unclear how they differ and when should the former be used over the latter. In this article I’d like to go over the distinction between the two concepts in greater detail than most explanations on the web do and then show some real world examples. I am going to use Scala in all of my code snippets.

  1. Currying
  2. Partial Function Application
  3. Use Cases
  4. Conclusion

Currying

In a nutshell, currying is the process of decomposing a function of multiple arguments into a chained sequence of functions of one argument. So, what does it exactly mean? Consider the following function that calculates the y-coordinate of a straight line:

\[f(a, b, x) = a * x + b\]

The function above has three arguments. If we want to transform this function into a chain of functions each taking a single parameter we’ll have to use currying. Function f(a, b, x) can be represented as a composition of three maps that each takes one argument:

\[g(x) = x \mapsto (b \mapsto (a \mapsto f(a, b, x)))\]

Here g(x) is a function that returns another function (expression on the right side). The pipe-arrow symbol, which is equivalent to => in Scala, means that the argument x is mapped to another function (think of it as a shorter way to define a function):

\[h(b) = b \mapsto (a \mapsto f(a, b, x))\]

Function h(b) maps b to another function:

\[j(a) = a \mapsto f(a, b, x)\]

Finally, function j(a) maps a to our initial function f(a, b, x).

Now let’s create a function that calculates the y-coordinate for a line that goes through (0, 0) at a 45° angle:

\[a = 1\] \[b = 0\] \[g(x) = x \mapsto (0 \mapsto (1 \mapsto f(0, 1, x))) = 1 * x + 0 = x\]

Yay! We just converted our general function for a straight line into a curried function with preset properties that can be reused later.

Another last bit of formalism—a more general definition of a curried function:

\[f \colon (X \times Y \times Z) \to N\] \[\mbox{curry}(f) \colon X \to (Y \to (Z \to N))\]

It’s basically the same thing that we defined before but without any “implementation” details. In this definition we can see that function f takes three arguments X, Y, and Z and then returns some value N. The curried version of the function returns another function that maps X to another function Y → (Z → N) that maps Y to yet another function Z → N that finally returns a value N.

That was a pretty tedious explanation but it’s important to understand the essence of currying on a simple example before comparing it to partial function application. How do curried functions look in the code? In Scala we use multiple parameter lists to implement currying:

def line(a: Int, b: Int, x: Int): Int = a * x + b

def curriedLine(a: Int)(b: Int)(x: Int): Int = line(a, b, x)

def defaultLine(x: Int): Int = curriedLine(1)(0)(x)

defaultLine(5) // returns `5`

The curriedLine method does all the currying work here. Its signature is Int => (Int => (Int => Int)). This means that curriedLine takes an integer as a parameter and returns another function that takes an integer…and so on. Does this remind you of something? It’s the exact definition of a curried function that we discovered just a few moments ago: X → (Y → (Z → N)).

In Scala you can convert any function into a curried function by applying curried to it:

def line(a: Int, b: Int, x: Int): Int = a * x + b

def curriedLine = (line _).curried

This version of curriedLine is the equivalent of the previously defined curriedLine with the Int => (Int => (Int => Int)) signature.

Partial Function Application

Partially applied functions are really similar to currying at first glance but there are some significant differences. Consider our function for a straight line again:

\[f(a, b, x) = a * x + b\]

Partial application of this function will result in another function of two arguments. The third argument is fixed, or set in advance. Here is a partially applied function with a preset value of a:

\[g(b, x) = f(2, b, x) = 2 * x + b\]

Here is the same thing in a more general notation:

\[f \colon (X \times Y \times Z) \to N\] \[\mbox{partial}(f) \colon (Y \times Z) \to N\]

Can you see the major difference between currying and partial application?

Partially applied functions always return the value of the original function as opposed to sequentially mapping its arguments to nested functions until the last one returns the value of the original function.

Here is what a partially applied function looks like in Scala:

def line(a: Int, b: Int, x: Int): Int = a * x + b

def partialLine = (b: Int, x: Int) => line(2, b, x)

partialLine(0, 1) // returns `2`

The signature of partialLine is (Int, Int) => Int, which is the same thing as (Y × Z) → N that we discovered above. A shortcut for creating a partially applied function in Scala is to use the underscore symbol:

def partialLine = line(2, _: Int, _: Int)

This code will generate exactly the same partially applied function as before.

Use Cases

So, how can you use currying and partial function application in your code? The following examples are going to be somewhat more Scala-focused than the rest of the article but in a lot of cases they can be directly applied in other functional languages.

The obvious benefit of currying and partial function application is the ability to create specialized functions based on general functions without introducing new code and repeating ourselves. When should one be used over the other? Basically, you want to use partially applied functions for all of your specialized functions unless you are dealing with blocks, dynamic default parameter values, smart type inference, or multiple varargs. For these cases it’s better to use currying. I’ll go over every single one of them to show how to do it.

Blocks

Currying should be used over partially applied functions when the last argument of the method or function is a function, so we can enjoy the syntactic superiority of blocks that are so common in Scala programs. For example, take a look at the foldLeft method from the TraversableOnce Scala trait:

def foldLeft[B](z: B)(op: (B, A) => B): B = {
  var result = z
  this foreach (x => result = op(result, x))
  result
}

Currying allows us to use the block syntax anywhere in the code. Consider the following example that computes squares of integers:

Vector(1, 2, 3).foldLeft(Vector[Int]()) { (is, i) =>
  is :+ i * i
}

Without currying, the code would look like this:

Vector(1, 2, 3).foldLeft(Vector[Int](), { (is, i) =>
  is :+ i * i
})

It’s obviously not as appealing and clean as the curried version.

Default Parameter Values

Another good use case for currying is referring to a parameter from a subsequent parameter default value. For example:

case class Resource(createdAt: Long)
case class Record

def loadRecordsFor(r: Resource)(since: Long = r.createdAt): List[Record] = ???

val r = Resource(System.currentTimeMillis)
val rs = loadRecordsFor(r)()

Here we want to load all records of some sort for a resource. By default, we are only interested in the records that were created after the resource was created. However, in some cases we’d want to load resource records that were created, say, in the past day. In these situations we can provide an optional parameter that will offset the search range by a custom date:

loadRecordsFor(r)(System.currentTimeMillis - 86400000)

The problem with this solution is that we still have to use an extra set of parenthesis, or a _, even if we are okay with using the default parameter value for since. If you want your function calls to look even cleaner use implicits:

case class Resource(createdAt: Long)
case class Record

def loadRecordsFor(r: Resource)(implicit since: Long = r.createdAt): List[Record] = ???

val r = Resource(System.currentTimeMillis)
val rs = loadRecordsFor(r)

This way, thanks to Scala syntactic sugar, function calls remain clean, yet we have the ability to set a custom parameter. By the way, currying is the only way to use implicit parameters in Scala. This, for example, won’t compile:

def loadRecordsFor(r: Resource, implicit since: Long)

Type Inference

Currying is really useful for type inference. Consider the following function:

def customOp[T](a: T, b: T, op: (T, T) => T) = op(a, b)

Say, we want to make a function call like this:

customOp(2, 3, (a, b) => a + b)

The compiler will throw an error about insufficient type information. You’d have to specify types by hand:

customOp[Int](2, 3, (a, b) => a + b)

// or like this:

customOp(2, 3, (a: Int, b: Int) => a + b)

The curried version of the function allows the compiler to infer types on its own:

def customOp[T](a: T, b: T)(op: (T, T) => T) = op(a, b)

customOp(2, 3)((a, b) => a + b)

// or even shorter:

customOp(2, 3)(_ + _)

Nice and clean. This works because the curried function gets executed in two “stages” making the compiler infer types twice (once for each set of arguments).

Varargs

The last but not least reason to use currying is multiple varargs or varargs injected before other parameters. Let’s say, we want to create a custom println method that optionally capitalizes all passed strings. Since we always want to pass strings first and only then customize the output, we’ll have to use currying:

def printlnCap(ss: String*)(implicit capitalize: Boolean = false) = {
  ss.map(s => println(if (capitalize) s.capitalize else s))
  
  ()
}

printlnCap("foo", "bar") // outputs "foo" and "bar"

printlnCap("foo", "bar")(true) // outputs "Foo" and "Bar"

Pretty neat, huh?

Here is how multiple sets of varargs can be used with currying:

def productOfSums(as: Int*)(bs: Int*): Int = as.sum * bs.sum

productOfSums(1, 2, 3)(4, 5, 6, 7, 8) // returns 180

Conclusion

Hopefully, you discovered some new tricks and deepened your understanding of functional programming after reading this article. It was very fun to write it and I learned a few things myself in the process. Let me know if you have any corrections or comments—I’m always open to feedback.