How to use partially applied functions in Scala

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 9.6, “How to use partially applied functions in Scala.”

Problem

You want to eliminate repetitively passing variables into a Scala function by (a) passing common variables into the function to (b) create a new function that is preloaded with those values, and then (c) use the new function, passing it only the unique variables it needs.

Solution

The classic example of a partially applied function begins with a simple sum function:

val sum = (a: Int, b: Int, c: Int) => a + b + c

There’s nothing special about this sum function, it’s just a normal function. But things get interesting when you supply two of the parameters when calling the function, but don’t provide the third parameter:

val f = sum(1, 2, _: Int)

Because you haven’t provided a value for the third parameter, the resulting variable f is a partially applied function. You can see this in the REPL:

scala> val sum = (a: Int, b: Int, c: Int) => a + b + c
sum: (Int, Int, Int) => Int = <function3>

scala> val f = sum(1, 2, _: Int)
f: Int => Int = <function1>

The result in the REPL shows that f is a function that implements the function1 trait, meaning that it takes one argument. Looking at the rest of the signature, you see that it takes an Int argument, and returns an Int value.

When you give f an Int, such as the number 3, you magically get the sum of the three numbers that have been passed into the two functions:

scala> f(3)
res0: Int = 6

The first two numbers (1 and 2) were passed into the original sum function; that process created the new function named f, which is a partially applied function; then, some time later in the code, the third number (3) was passed into f.

Discussion

In functional programming languages, when you call a function that has parameters, you are said to be applying the function to the parameters. When all the parameters are passed to the function — something you always do in Java — you have fully applied the function to all of the parameters. But when you give only a subset of the parameters to the function, the result of the expression is a partially applied function.

As demonstrated in the example, this partially applied function is a variable that you can pass around. This variable is called a function value, and when you later provide all the parameters needed to complete the function value, the original function is executed and a result is yielded.

This technique has many advantages, including the ability to make life easier for the consumers of a library you create. For instance, when working with HTML, you may want a function that adds a prefix and a suffix to an HTML snippet:

def wrap(prefix: String, html: String, suffix: String) = {
    prefix + html + suffix
}

If at a certain point in your code, you know that you always want to add the same prefix and suffix to different HTML strings, you can apply those two parameters to the function, without applying the html parameter:

val wrapWithDiv = wrap("<div>", _: String, "</div>")

Now you can call the new wrapWithDiv function, just passing it the HTML you want to wrap:

scala> wrapWithDiv("<p>Hello, world</p>")
res0: String = <div><p>Hello, world</p></div>

scala> wrapWithDiv("<img src=\"/images/foo.png\" />")
res1: String = <div><img src="/images/foo.png" /></div>

The wrapWithDiv function is preloaded with the <div> tags you applied, so it can be called with just one argument: the HTML you want to wrap.

As a nice benefit, you can still call the original wrap function if you want:

wrap("<pre>", "val x = 1", "</pre>")

You can use partially applied functions to make programming easier by binding some arguments — typically some form of local arguments — and leaving the others to be filled in.

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote for O’Reilly:

You can find the Scala Cookbook at these locations:

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.