Java.next: Currying and partial application

Add power and indirection to function dispatch

All of the Java.next languages include currying and partial application but implement them in different ways. This installment explains both techniques, distinguishes between them, and shows implementation details — and practical uses — in Scala, Groovy, and Clojure.

Share:

Neal Ford, Director / Software Architect / Meme Wrangler, ThoughtWorks

Photo of Neal FordNeal Ford is Director, Software Architect, and Meme Wrangler at ThoughtWorks, a global IT consultancy. He is also the designer and developer of applications, instructional materials, magazine articles, courseware, and video/DVD presentations, and he is the author or editor of books spanning a variety of technologies, including the most recent Presentation Patterns. He focuses on designing and building large-scale enterprise applications. He is also an internationally acclaimed speaker at developer conferences worldwide. Check out his website.



26 November 2013

Also available in Chinese Russian Japanese

Currying and partial application are language techniques derived from mathematics (based on work by 20th-century mathematician Haskell Curry and others). These techniques are present in various types of languages, and either or both are omnipresent in functional languages. Both currying and partial application give you the ability to manipulate the number of arguments to functions or methods, typically by supplying one or more default values for some arguments (known as fixing arguments). All of the Java.next languages include currying and partial application, but they implement them in different ways. In this installment, I explain the difference between the two techniques and show implementation details for Scala, Groovy, and Clojure, along with practical uses.

A note about terminology

For this installment's purposes, method and function are interchangeable. Object-oriented languages that support currying and partial application use methods. Similarly, function parameter and function argument are interchangeable. Because these concepts originated in mathematics, I use function and argument throughout, but that's not meant to imply that these techniques don't work on methods.

Open beta program for IBM SDK for Java 8

IBM Worklight Developer Edition download

Definitions and distinction

About this series

The Java™ legacy will be the platform, not the language. More than 200 languages run on the JVM, and it's inevitable that one of them will eventually supplant the Java language as the best way to program the JVM. This series explores three next-generation JVM languages: Groovy, Scala, and Clojure, comparing and contrasting new capabilities and paradigms, to provide Java developers a glimpse into their own near future.

To the casual observer, currying and partial application appear to have the same effect. With both, you can create a version of a function with pre-supplied values for some of the arguments:

  • Currying describes the conversion of a multi-argument function into a chain of single-argument functions. It describes the transformation process, not the invocation of the converted function. The caller can decide how many arguments to apply, thereby creating a derived function with that smaller number of arguments.
  • Partial application describes the conversion of a multi-argument function into one that accepts fewer arguments, with values for the elided arguments supplied in advance. The technique's name is apt: It partially applies some arguments to a function, returning a function with a signature that consists of the remaining arguments.

With both currying and partial application, you supply argument values and return a function that's invokable with the missing arguments. But currying a function returns the next function in the chain, whereas partial application binds argument values to values that you supply during the operation, producing a function with a smaller arity (number of arguments). This distinction becomes clearer when you consider functions with arity greater than two. For example, the fully curried version of the process(x, y, z) function is process(x)(y)(z), where both process(x) and process(x)(y) are functions that accept a single argument. If you curry only the first argument, the return value of process(x) is a function that accepts a single argument that in turn accepts a single argument. In contrast, with partial application, you are left with a function of smaller arity. Using partial application for a single argument on process(x, y, z) yields a function that accept two arguments: process(y, z).

The two techniques' results are often the same, but the distinction is important and often misconstrued. To complicate matters further, Groovy implements both partial application and currying but calls both currying. And Scala has both partially applied functions and PartialFunctions, which are distinct concepts despite the similar names.


In Scala

Scala supports currying and partial application, along with a trait that gives you the ability to define constrained functions.

Currying

In Scala, functions can define multiple argument lists as sets of parentheses. When you call a function with fewer than its defined number of arguments, the return is a function that takes the missing argument lists as its arguments. Consider the example from the Scala documentation that appears in Listing 1.

Listing 1. Scala's currying of arguments
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
    if (xs.isEmpty) xs
    else if (p(xs.head)) xs.head :: filter(xs.tail, p)
    else filter(xs.tail, p)

def modN(n: Int)(x: Int) = ((x % n) == 0)

val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
println(filter(nums, modN(2)))
println(filter(nums, modN(3)))

In Listing 1, the filter() function recursively applies the passed filter criteria. The modN() function is defined with two argument lists. When I call modN by using filter(), I pass a single argument. The filter() function accepts as its second argument a function with an Int argument and a Boolean return, which matches the signature of the curried function that I pass.

Partially applied functions

In Scala you can also partially apply functions, as shown in Listing 2.

Listing 2. Partially applying functions in Scala
def price(product : String) : Double =
  product match {
    case "apples" => 140
    case "oranges" => 223
}

def withTax(cost: Double, state: String) : Double =
  state match {
    case "NY" => cost * 2
    case "FL" => cost * 3
}


val locallyTaxed = withTax(_: Double, "NY")
val costOfApples = locallyTaxed(price("apples"))

assert(Math.round(costOfApples) == 280)

In Listing 2, I first create a price function that returns a mapping between product and price. Then I create a withTax() function that accepts cost and state as arguments. However, within a particular source file, I know that I will work exclusively with one state's taxes. Rather than "carry" the extra argument for every invocation, I partially apply the state argument and return a version of the function in which the state value is fixed. The locallyTaxed function accepts a single argument, the cost.

Partial (constrained) functions

The Scala PartialFunction trait is designed to work seamlessly with pattern matching. (Read about pattern matching in the "Either trees and pattern matching" installment of my Functional thinking series.) Despite the similarity in name, this trait does not create a partially applied function. Instead, you can use it to define a function that works only for a defined subset of values and types.

Case blocks are one way to apply partial functions. Listing 3 uses Scala's case without the traditional corresponding match operator.

Listing 3. Using case without match
val cities = Map("Atlanta" -> "GA", "New York" -> "New York",
  "Chicago" -> "IL", "San Francsico " -> "CA", "Dallas" -> "TX")

cities map { case (k, v) => println(k + " -> " + v) }

In Listing 3, I create a map of city and state correspondence. Then I invoke the map function on the collection, and map in turn pulls apart the key-value pairs to print them. In Scala, a code block that contains case statements is one way of defining an anonymous function. You can define anonymous functions more concisely without using case, but the case syntax provides the additional benefits that Listing 4 illustrates.

Listing 4. Differences between map and collect
List(1, 3, 5, "seven") map { case i: Int ? i + 1 } // won't work
// scala.MatchError: seven (of class java.lang.String)

List(1, 3, 5, "seven") collect { case i: Int ? i + 1 }
// verify
assert(List(2, 4, 6) == (List(1, 3, 5, "seven") collect { case i: Int ? i + 1 }))

In Listing 4, I can't use map on a heterogeneous collection with case: I receive a MatchError as the function tries to increment the seven string. But collect works correctly. Why the disparity and where did the error go?

Case blocks define partial functions, but not partially applied functions. Partial functions have a limited range of allowable values. For example, the mathematical function 1/x is invalid if x = 0. Partial functions offer a way to define constraints for allowable values. In the collect example in Listing 4, the case is defined for Int, but not for String, so the seven string isn't collected.

To define a partial function, you can also use the PartialFunction trait, as illustrated in Listing 5.

Listing 5. Defining a partial function in Scala
val answerUnits = new PartialFunction[Int, Int] {
    def apply(d: Int) = 42 / d
    def isDefinedAt(d: Int) = d != 0
}

assert(answerUnits.isDefinedAt(42))
assert(! answerUnits.isDefinedAt(0))

assert(answerUnits(42) == 1)
//answerUnits(0)
//java.lang.ArithmeticException: / by zero

In Listing 5, I derive answerUnits from the PartialFunction trait and supply two functions: apply() and isDefinedAt(). The apply() function calculates values. I use isDefinedAt()— a required method for a PartialFunction— to define constraints that determine arguments' suitability.

Because you can also implement partial functions with case blocks, answerUnits from Listing 5 can be written more concisely, as shown in Listing 6.

Listing 6. Alternative definition for answerUnits
def pAnswerUnits: PartialFunction[Int, Int] =
    { case d: Int if d != 0 => 42 / d }

assert(pAnswerUnits(42) == 1)
//pAnswerUnits(0)
//scala.MatchError: 0 (of class java.lang.Integer)

In Listing 6, I use case in conjunction with a guard condition to constrain values and supply results simultaneously. One notable difference from Listing 5 is the MatchError (rather than ArithmeticException) — because Listing 6 uses pattern matching.

Partial functions aren't limited to numeric types. You can use all types, including Any. Consider the implementation of an incrementer, shown in Listing 7.

Listing 7. Defining an incrementer in Scala
def inc: PartialFunction[Any, Int] =
    { case i: Int => i + 1 }

assert(inc(41) == 42)
//inc("Forty-one")
//scala.MatchError: Forty-one (of class java.lang.String)

assert(inc.isDefinedAt(41))
assert(! inc.isDefinedAt("Forty-one"))

assert(List(42) == (List(41, "cat") collect inc))

In Listing 7, I define a partial function to accept any type of input (Any), but choose to react to a subset of types. However, notice that I can also call the isDefinedAt() function for the partial function. Implementers of the PartialFunction trait who use case can call isDefinedAt(), which is implicitly defined. In Listing 4, I illustrated that map and collect behave differently. The behavior of partial functions explains the difference: collect is designed to accept partial functions and to call the isDefinedAt() function for elements, ignoring those that don't match.

Partial functions and partially applied functions in Scala are similar in name, but they offer a different set of orthogonal features. For example, nothing prevents you from partially applying a partial function.


In Groovy

I cover currying and partial application in Groovy in some detail as part of my Functional thinking series in "Thinking functionally, Part 3." Groovy implements currying through the curry() function, which originates from the Closure class. Despite the name, curry() actually implements partial application by manipulating closure blocks underneath. However, you can simulate currying by using partial application to reduce a function to a series of partially applied single-argument functions, as shown in Listing 8.

Listing 8. Groovy's partial application and currying
def volume = { h, w, l -> return h * w * l }
def area = volume.curry(1)
def lengthPA = volume.curry(1, 1) //partial application
def lengthC = volume.curry(1).curry(1) // currying

println "The volume of the 2x3x4 rectangular solid is ${volume(2, 3, 4)}"
println "The area of the 3x4 rectangle is ${area(3, 4)}"
println "The length of the 6 line is ${lengthPA(6)}"
println "The length of the 6 line via curried function is ${lengthC(6)}"

In Listing 8, in both length cases, I use the curry() function to apply arguments partially. But with lengthC, I create the illusion of currying by partially applying arguments until a chain of single-argument functions remains.


In Clojure

Clojure includes the (partial f a1 a2 ...) function, which takes a function f and a fewer-than-required number of arguments and returns a partially applied function that's invokable when you supply the remaining arguments. Listing 9 shows two examples.

Listing 9. Clojure's partial application
(def subtract-from-hundred (partial - 100))

(subtract-from-hundred 10)      ; same as (- 100 10)
; 90

(subtract-from-hundred 10 20)   ; same as (- 100 10 20)
; 70

In Listing 9, I define a subtract-from-hundred function as the partially applied - operator (operators in Clojure are indistinguishable from functions) and supply 100 as the partially applied argument. Partial application in Clojure works for both single- and multiple-argument functions, as shown in the two examples in Listing 9.

Because Clojure is dynamically typed and supports variable argument lists, currying isn't implemented as a language feature. Partial application handles the necessary cases. However, the namespace private (defcurried ...) function that Clojure added to the reducers library (see Resources), enables much-easier definition of some functions within that library. Given the flexible nature of Clojure's Lisp heritage, it is trivial to widen the use of (defcurried ...) to a broader scope.


Common uses

Despite the tricky definitions and myriad implementation details, currying and partial application do have a place in real-world programming.

Function factories

Currying (and partial application) work well for places where you implement a factory function in traditional object-oriented languages. As an example, Listing 10 implements a simple adder function in Groovy.

Listing 10. Adder and incrementer in Groovy
def adder = { x, y -> x + y}
def incrementer = adder.curry(1)

println "increment 7: ${incrementer(7)}" // 8

In Listing 10, I use the adder() function to derive the incrementer function. Similarly, in Listing 2, I use partial application to create a locally more concise version of the function.

Template Method design pattern

One of the Gang of Four design patterns is the Template Method pattern. Its purpose is to help you define algorithmic shells that use internal abstract methods to enable later implementation flexibility. Partial application and currying can solve the same problem. Using partial application to supply known behavior and leaving the other arguments free for implementation specifics mimics the implementation of this object-oriented design pattern.

Implicit values

A common case, similar to Listing 2, is one in which you have a series of function calls with similar argument values. For example, when you interact with a persistence framework, you must pass the data source as the first argument. By using partial application, you can supply the value implicitly, as shown in Listing 11.

Listing 11. Using partial application to supply implicit values
(defn db-connect [data-source query params]
      ...)

(def dbc (partial db-connect "db/some-data-source"))

(dbc "select * from %1" "cust")

In Listing 11, I use the convenience dbc function to access the data functions without needing to provide the data source, which is supplied automatically. The essence of object-oriented programming — the idea of an implicit this context that appears as if by magic in every function — can be implemented by using currying to supply this to every function, making it invisible to consumers.

Conclusion

Currying and partial application appear in all the Java.next languages in various forms. You can use either of these techniques to make more-concise function definitions, supply implicit values, and build function factories.

In the next installment, I show the surprising similarities among all the Java.next languages' functional programming capabilities — along with the sometimes wildly different implementation details for those capabilities.

Resources

Learn

  • Scala: Scala is a modern, functional language on the JVM.
  • Groovy: Groovy is a dynamic variant of the Java language, with updated syntax and capabilities.
  • Clojure: Clojure is a modern, functional Lisp that runs on the JVM.
  • What's the difference between Currying and Partial Application?: Raganwald, a popular developer blog, defines the difference between currying and partial application.
  • reducers: The reducers library is a powerful Clojure extension that enables sophisticated concurrent access for operations such as map.
  • Functional thinking: Explore functional programming in Neal Ford's series on developerWorks.
  • "Language designer's notebook:" In this developerWorks series, Java Language Architect Brian Goetz explores some language design issues that have presented challenges for the evolution of the Java language in Java SE 7, Java SE 8, and beyond.
  • developerWorks Java technology zone: Find hundreds of articles about every aspect of Java programming.

Get products and technologies

Discuss

  • Get involved in the developerWorks community. Connect with other developerWorks users as you explore the developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=954134
ArticleTitle=Java.next: Currying and partial application
publish-date=11262013