Groovy Functional Programming - Currying
One of the design techniques used in functional programming is to create a generic functions and derive special functions from the generic ones by fixing some of the arguments. To understand this consider the following use-case.
We want to be able to double, triple and quadruple numbers. We can write the following closures.
def doubler = { number ->
number * 2
}
def triple = { number ->
number * 3
}
def quadruple = { number ->
number * 4
}
println doubler(10) // 20
println triple(10) // 30
println quadruple(10) // 40
If you are not familiar with closures, this article has the necessary details.
Let's create a generic closure to multiply two numbers and achieve the same results.
def multiply = { times, number ->
times * number
}
println multiply(10, 2) // 20
println multiply(10, 3) // 30
println multiply(10, 4) // 40
It works, but not as intuitive or readable as before. Now let's use currying to derive the closures which can double, triple and quadruple.
def doubler = multiply.curry(2)
def triple = multiply.curry(3)
def quadruple = multiply.curry(4)
println doubler(10) // 20
println triple(10) // 30
println quadruple(10) // 40
Here the method curry
creates a new closure by fixing the first argument for multiply
. Thus the returned closure has only one argument, which is number
.
While curry
starts fixing the arguments from left, Groovy also provides other variants of currying.
The method rcurry
can be used if you want to fix values for the parameters of right most ones.
rcurry
does not apply values from right to left. If your original closure has 3 parameters, and if you want to fix the second and third parameters, the first argument to rcurry
should be the value for the second parameter, followd by the value for the third parameter.
The method ncurry
will fix parameters starting from a specified position
Note: Some languages/ libraries distinguish between partial application and currying. In such cases currying is fixing parameters one at a time, while with partial application, you can fix multiple parameters in a single shot. However in Groovy, no such distinctions exist.
You may want to take a look at slides from my FunctionalConf talk for more examples.