Partially-Applied Functions (and Currying)

My motivations for writing this lesson are a little different than usual. Typically I think, “You’ll want to know this feature so you can use it like ___,” but the first motivation for this lesson goes like this: You’ll want to know about the concept of “currying” because experienced FP developers talk about it a lot, especially if they have Haskell programming experience. (I did mention that Haskell was named after Haskell Curry, didn’t I?)

A second motivation is that the concept of currying is related to the multiple parameter groups I showed in the previous lesson come from.

The primary motivation for writing this lesson is that having multiple parameter groups make it a little easier to create partially-applied functions, and these can be useful in your FP code.

I’ll cover all of these topics in this lesson.

Given that introduction, the goals of this lesson are:

  • Provide a definition of currying

  • Show how to create partially-applied functions from functions that have (a) multiple parameter groups or (b) single parameter groups

I’ll also show how to create “curried” functions from regular functions, and show how Scala gets these features to work with the JVM.

When I first got started in FP, I got lost in some of the nomenclature, and “currying” was a particularly deep rabbit’s hole of “Time in My Life I Wish I Had Spent Differently.”

All that the theory of currying means is that a function that takes multiple arguments can be translated into a series of function calls that each take a single argument. In pseudocode, this means that an expression like this:

result = f(x)(y)(z)

is mathematically the same as something like this:

f1 = f(x)
f2 = f1(y)
result = f2(z)

That’s all it means. The Wikipedia page on Currying describes the theory of currying like this:

In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument.

They later state:

There are analytical techniques that can only be applied to functions with a single argument. Practical functions frequently take more arguments than this.

In my daily working life, this sort of theory usually isn’t important. It’s one of those things that’s “nice to know,” but the important things are really (a) how this impacted the design of the Scala language, and (b) what you can do because of this theory.

In Scala this seems to fit most naturally with functions that have multiple input parameters groups, and I’ll demonstrate that in this lesson.

In the remainder of this lesson I’ll occasionally use the acronym “PAF” to mean “partially-applied function.”

To understand PAFs, I’ll start with two definitions from this online JavaScript course:

  1. Application: The process of applying a function to its arguments in order to produce a return value.

    As in algebra, in FP you say that “a function is applied to its arguments,” so “Application” in this context can also be called “Full Application,” or “Complete Application.”

  1. Partial Application: This is the process of applying a function to some of its arguments. A partially-applied function gets returned for later use. In other words, a PAF is a function that takes a function with multiple parameters and returns a function with fewer parameters.

The best way to explain PAFs is with examples, so let’s look at a few.

The following example shows how PAFs work. In the first step, you define a function with multiple parameter groups:

scala> def plus(a: Int)(b: Int) = a + b
plus: (a: Int)(b: Int)Int

Next, rather than giving the function all of the parameters in the two parameter groups it specifies, you give it (a) the parameter for the first group (a), and (b) a placeholder for the parameter in the second list, the ubiquitous underscore character:

scala> def plus2 = plus(2)(_)
plus2: Int => Int

The REPL output shows that this creates a new function named plus2 which has the type Int => Int. This means that plus2 takes an Int as input, and returns an Int as a result.

At this point you can think of plus2 as looking like this:

def plus(b: Int) = 2 + b

plus2 has been “seeded” with the initial Int value 2, and now it’s just sitting there, waiting for another Int value that it can add to it. Let’s give it another 2:

scala> plus2(2)
res0: Int = 4

Here’s what it looks like when you give it a 3:

scala> plus2(3)
res1: Int = 5

As this shows, plus2 gladly adds 2 to any Int it is given.

Before I move on to another example, note that you can create plus2 in either of these ways:

def plus2 = plus(2)(_)
def plus2 = plus(2)_

I prefer the first approach, but some people prefer the second approach.

The general benefit that this approach gives you is that it’s a way to create specialized methods from more general methods. I demonstrate that in the Scala Cookbook, and I’ll share a variation of that example here.

When you’re emitting HTML from Scala code, a wrap function that adds a prefix and a suffix to an HTML snippet can be really useful:

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

You can use that function to do something like this, where I wrap a string in opening and closing <div> tags:

val hello = "Hello, world"
val result = wrap("<div>")(hello)("</div>")

Of course that <div> tag can be more complicated, such as specifying a CSS class or id, but I’m keeping this simple.

It turns out that wrap is a really nice, general function, so you can wrap text in DIV tags, P tags, SPAN tags, etc. But if you’re going to be wrapping a lot of strings with DIV tags, what you probably want is a more specific wrapWithDiv function. This is a great time to use a partially-applied function, because that’s what they do, helping you create a specific function from a general function:

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

Now you can call wrapWithDiv, 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>

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

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

and you can also create other, more-specific functions:

val wrapWithPre = wrap("<pre>")(_: String)("</pre>")

It’s worth noting that you make a more specific function by “seeding” the more general function with one or more initial parameters. That is, you partially-apply parameters to the general function to make the specific function.

It’s necessary to specify the type of the missing parameter, as I did in this code:

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

If you don’t specify the type, you’ll get a compiler error that looks like this:

scala> val wrapWithDiv = wrap("<div>")(_)("</div>")
<console>:11: error: missing parameter type for 
expanded function ((x$1) => wrap("<div>")(x$1)("</div>"))
       val wrapWithDiv = wrap("<div>")(_)("</div>")
                                       ^

As a summary, PAFs give you this capability:

  • You write a general function

  • You create a specific function from the general function

  • You still have access to both functions, and you kept your code “DRY” — you didn’t copy and paste code to make the new function

As a fun example of some things you can do with PAFs, the “partially-applied functions” section of the Scala Exercises website demonstrates that you can create curried functions from “normal” Scala functions. For instance, you can start with a “normal” one-parameter group function like this:

def add(x: Int, y: Int) = x + y

Then they show that you can create a Function2 instance from add by adding an underscore after it, like this:

scala> val addFunction = add _
addFunction: (Int, Int) => Int = <function2>

They then prove that it’s a Function2 instance like this:

(add _).isInstanceOf[Function2[_, _, _]]

This technique of converting a def method into a true function uses a Scala technology known as “Eta Expansion.” I mentioned this in the previous lessons, and I also discuss it in depth in the appendix titled, “The Differences Between ‘def’ and ‘val’ When Defining Functions.”

Then they create a “curried” function from that Function2 instance:

val addCurried = (add _).curried

Now you can use the new curried function like this:

addCurried(1)(2)

As this shows, calling the curried method on the add function instance creates a new function that has two parameter groups. (So, a curried function can be thought of as a function with multiple parameter groups.)

It’s also easy to create a partially-applied function from the curried function, like this:

val addCurriedTwo = addCurried(2)    // create a PAF
addCurriedTwo(10)                    // use the PAF

You can see how all of those steps work by pasting the code into the REPL:

scala> def add(x: Int, y: Int) = x + y
add: (x: Int, y: Int)Int

scala> (add _).isInstanceOf[Function2[_, _, _]]
res0: Boolean = true

scala> val addCurried = (add _).curried
addCurried: Int => (Int => Int) = <function1>

scala> addCurried(1)(2)
res1: Int = 3

scala> val addCurriedTwo = addCurried(2)
addCurriedTwo: Int => Int = <function1>

scala> addCurriedTwo(10)
res2: Int = 12

Personally, I mostly use curried functions to create control structures — as I demonstrated with whilst and ifBothTrue in the previous lesson. So, at the moment, this is a technique I know about, but have not used.

So far I’ve shown that you can create a partially-applied function with functions that have multiple parameter groups, but because Scala is really convenient, you can create PAFs with single parameter group functions as well.

To do this, first define a function as usual, with one parameter group:

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

Then create a PAF by applying the first and third parameters, but not the second:

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

The wrapWithDiv function you create in this manner works the same as the wrapWithDiv function created in the previous example:

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

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

If you’re interested in how things work under the covers, a good question at this point is, “How can this stuff possibly work with the JVM?” The JVM certainly wasn’t written to account for things like currying and PAFs, so how does any of this work?

A short answer is that (a) the Scala compiler “uncurries” your code, and (b) you can see this during the compilation process. For example, write a little Scala class like this:

class Currying {
    def f1(a: Int, b: Int) = { a + b }   // 1 param group
    def f2(a: Int)(b: Int) = { a + b }   // 2 param groups
}

Then compile that class with this command:

$ scalac -Xprint:all Currying.scala

if you dig through the end of that output, you’ll see that the Scala compiler has an “uncurry” phase. A short version of the tail end of the compiler output looks like this:

[[syntax trees at end of typer]] // Currying.scala
package <empty> {
  class Currying extends scala.AnyRef {
    def <init>(): Currying = {
      Currying.super.<init>();
      ()
    };
    def f1(a: Int, b: Int): Int = a.+(b);
    def f2(a: Int)(b: Int): Int = a.+(b)
  }
}

.
.
.

[[syntax trees at end of uncurry]] // Currying.scala
package <empty> {
  class Currying extends Object {
    def <init>(): Currying = {
      Currying.super.<init>();
      ()
    };
    def f1(a: Int, b: Int): Int = a.+(b);
    def f2(a: Int, b: Int): Int = a.+(b)
  }
}

As that output shows, I wrote the two functions f1 and f2 differently, but after the compiler’s “uncurry” phase they end up looking the same.

Things might look more interesting in the output if I had created a partially-applied function, but I’ll leave that as an exercise for the reader.

If you want to dig into this more, it can also help to know what the Scala compiler phases are. This command:

$ scalac -Xshow-phases

shows that the phases in Scala 2.11 are:

    phase name  id  description
    ----------  --  -----------
        parser   1  parse source into ASTs, perform simple desugaring
         namer   2  resolve names, attach symbols to named trees
packageobjects   3  load package objects
         typer   4  the meat and potatoes: type the trees
        patmat   5  translate match expressions
superaccessors   6  add super accessors in traits and nested classes
    extmethods   7  add extension methods for inline classes
       pickler   8  serialize symbol tables
     refchecks   9  reference/override checking, translate nested objects
       uncurry  10  uncurry, translate function values to anonymous classes
     tailcalls  11  replace tail calls by jumps
    specialize  12  @specialized-driven class and method specialization
 explicitouter  13  this refs to outer pointers
       erasure  14  erase types, add interfaces for traits
   posterasure  15  clean up erased inline classes
      lazyvals  16  allocate bitmaps, translate lazy vals into lazified defs
    lambdalift  17  move nested functions to top level
  constructors  18  move field definitions into constructors
       flatten  19  eliminate inner classes
         mixin  20  mixin composition
       cleanup  21  platform-specific cleanups, generate reflective calls
    delambdafy  22  remove lambdas
         icode  23  generate portable intermediate code
           jvm  24  generate JVM bytecode
      terminal  25  the last phase during a compilation run

As that shows, the “uncurry” phase “translates function values to anonymous classes.”

The concepts of currying and partially-applied functions are closely related, but they aren’t exactly the same. As I wrote at the beginning, currying is defined like this:

A function that takes multiple arguments can be translated into a series of function calls that each take a single argument.

This is particularly important in a language like Haskell, where all functions are technically curried functions. In Scala this is generally a theoretical thing that’s good to know about, and it’s good to know that you can create a curried function from an uncurried function, but these aren’t “core” features you absolutely need to know to write code in Scala.

A partially-applied function on the other hand is a function that you manually create by supplying fewer parameters than the initial function defines. As I showed in this lesson, you can create the PAF plus2 like this:

def plus(a: Int)(b: Int) = a + b
def plus2 = plus(2)(_)

and you can create wrapWithDiv as a PAF like this:

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

If for some reason you want to partially-apply one parameter out of three, you can also do this:

def add(a: Int)(b: Int)(c: Int) = a + b + c
val add2NumbersTo10 = add(10)(_: Int)(_: Int)

So both concepts are related to multiple parameter groups, but in general, I use PAFs more often than I concern myself with curried functions.

As I mentioned at the beginning of this lesson, don’t get bogged down in the precise meaning of things like “curried functions.” It is good to know how multiple input parameter groups work because it’s a technique that is used a lot in Scala/FP, but don’t get lost in worrying about the exact meaning of currying like I did. Understanding how multiple parameter groups work is the important thing.

This lesson covered the following topics:

  • It provides a definition of currying

  • It shows how to create partially-applied functions from functions that have (a) multiple parameter groups or (b) single parameter groups

It also shows how to create “curried” functions from regular functions, and provided a little look at how Scala gets these features to work with the JVM.

I’ve covered a lot of Scala/FP background material so far, but occasionally I had to mix in a few var fields in my examples because that’s the only way to solve certain problems with the tools I’ve shown so far.

Well, no more of that.

In the next few lessons things are going to be fun, as I get to cover recursion. Once you understand recursive calls, I think you’ll find that they’re a natural way to think about writing iterative algorithms.

Once I cover recursion you’ll then be very close to handling many more FP concepts, the first of which will be how to handle “state” in FP applications. But to handle state in an FP manner, you’ll need to know how to write recursive functions …

Here are a few more resources related to currying and partially-applied functions.

These discussions on StackOverflow and StackExchange also provide a little more insight:

results matching ""

    No results matching ""