- 12.1 Functions as Values
- 12.2 Anonymous Functions
- 12.3 Parameters That Are Functions
- 12.4 Parameter Inference
- 12.5 Useful Higher-Order Functions
- 12.6 Closures
- 12.7 Interoperability with Lambda Expressions
- 12.8 Currying
- 12.9 Methods for Composing, Currying, and Tupling
- 12.10 Control Abstractions
- 12.11 Nonlocal Returns
- Exercises
12.8 Currying
Currying (named after logician Haskell Brooks Curry) is the process of turning a function with two parameters into a function with one parameter. That function returns a function that consumes the second argument.
Huh? Let’s look at an example. This function has two parameters:
val mul = (x: Int, y: Int) => x * y
This function has one parameter, yielding a function with one parameter:
val mulOneAtATime = (x: Int) => ((y: Int) => x * y)
To multiply two numbers, you call
mulOneAtATime(6)(7)
Strictly speaking, the result of mulOneAtATime(6) is the function (y: Int) => 6 * y. That function is applied to 7, yielding 42.
When you use def, there is a shortcut for defining such curried methods in Scala:
def divOneAtATime(x: Int)(y: Int) = x / y
As you can see, multiple parameters are just a frill, not an essential feature of a programming language. That’s an amusing theoretical insight, but it has one practical use in Scala. Sometimes, you can use currying for a method parameter so that the type inferencer has more information.
Here is a typical example. The corresponds method can compare whether two sequences are the same under some comparison criterion. For example,
val a = Array("Mary", "had", "a", "little", "lamb") val b = Array(4, 3, 1, 6, 5) a.corresponds(b)(_.length == _)
Note that the function _.length == _ is passed as a curried parameter, in a separate set of (...). When you look into the Scaladoc, you will see that corresponds is declared as
def corresponds[B](that: Seq[B])(p: (A, B) => Boolean): Boolean
The that sequence and the predicate function p are separate curried parameters. The type inferencer can figure out what B is from the type of that, and then it can use that information when analyzing the function that is passed for p.
In our example, that is an Int sequence. Therefore, the predicate is expected to have type (String, Int) => Boolean. With that information, the compiler can accept _.length == _ as a shortcut for (a: String, b: Int) => a.length == b.