Curried Closures in groovy

15 / Jan / 2011 by Gautam Malhotra 0 comments

There’s a feature that adds spice to Groovy—it’s called Curried Closures.
The term curry is taken from Haskell Curry, the mathematician who developed the concept of partial functions. Currying refers to taking multiple arguments into a function that takes many arguments, resulting in a new function that takes the remaining arguments and returns a result.
When we curry( ) a closure, we are asking the parameters to be prebound. That is, We are assigning value to the parameters of a closure. This can help remove redundancy or duplication in our code.
When calling the curry() method we need not supply the full complement of actual parameters. The curried call gives rise to the partial application of the closure. The partial application of a closure is another Closure object in which some values have been fixed.
For Example:-

def tellFortunes(closure)
{
Date date = new Date("12/16/2010" )
postFortune = closure.curry(date) 
//postFortune = {  fortune -> println "Fortune for Thu Dec 16 00:00:00 UTC 2010 is '${fortune}'"}
postFortune "This is the second parameter"     // implicit call
postFortune "They're features, not bugs"         // implicit call
}

//Call tellFortunes with a closure
tellFortunes() { date, fortune ->
println "Fortune for ${date} is '${fortune}'"
}
output:
Fortune for Thu Dec 16 00:00:00 UTC 2010 is 'This is the second parameter'
Fortune for Thu Dec 16 00:00:00 UTC 2010 is 'They're features, not bugs'

We have a function named tellFortunes that takes a closure. This closure has 2 parameters Date and fortune. Inside tellFortune Function we are prebound a closure parameter Date and assign it’s reference to a variable postFortune. Now we call postFortune with only 1 parameter which assign this value to the “fortune” parameter.

curry() assign values to the parameters from left to right. In order to assign the value from right to left we use rcurry() method.
For Example:-

def divide = { a, b -> a / b }
def  assignValueToParameterStartFromRightPosition  = divide.rcurry(2)
assignValueToParameterStartFromRightPosition(8)
output:
4
Example:
def sum = { a, b,c ->
println "a=" + a
println "b=" + b
println "c=" + c
}
def assignValueToParametersStartFromRightPosition = sum.rcurry(80,40)
assignValueToParametersStartFromRightPosition(20)
output:
a=20
b=80
c=40

In order to support for Closure currying at a given index, we use ncurry() method. Parameters are supplied from index position “n”
(index start from 0).
Below, we have a closure which is assigned to variable “divide”. Using ncurry() we assign the value to the parameter, which is at index “0”,in this case “a” is being assigned a value 80.

def divide = { a, b -> a / b }
def assignValueToParameterAtNthPosition = divide.ncurry(0,80)
assignValueToParameterAtNthPosition(8)
output:
10
Example:
def printParameters = { a, b, c ->
println "a=" + a
println "b=" + b
println "c=" + c
}
def assignValueToParameterAtNthPosition = printParameters.ncurry(1,80)
assignValueToParameterAtNthPosition(20,40)
output:
a=20
b=80
c=40

Closure composition
One of the important characteristics of closures is composition, wherein you can define one closure whose purpose is to combine other closures. Using composition, two or more simple closures can be combined to produce a more elaborate one.

Example:-
def multiply = { x, y -> return x * y }    
// closure
def triple = multiply.curry(3)            
// triple = { y -> return 3 * y }
def quadruple = multiply.curry(4) 
// quadruple = { y -> return 4 * y }
def composition = { f, g, x -> return f(g(x)) }
def twelveTimes = composition.curry(triple, quadruple)
def threeDozen = twelveTimes(3)
println "threeDozen: ${threeDozen}"		 
// threeDozen: 36

Use-Case:
Consider the problem of computing the net price of a specific Book item, taking into account the shop discount and any governmental taxes such as a value added tax. If we include this logic as part of the Book class, the resulting solution would probably be a hard-wired one. Because the bookshop could change the value of its discount or apply it to only a selection of its stock, such a solution would likely be too rigid.
Changing such rules are readily accommodated using Curried Closures.
We can use a set of simple closures to represent individual rules and then combine them in various ways using compositions. Finally, Map them to collections using computation patterns.

class Book {
    String name
    String author
    BigDecimal price
    String category
}

def book = new Book(name:'Groovy', author:'KenB', price:25, category:'CompSci')
def discountRate = 0.1
def taxRate = 0.17
//  book closures
def rMultiply     = { y, x -> return x * y }
def calcDiscountedPrice = rMultiply.curry(1 - discountRate)
def calcTax = rMultiply.curry(1 + taxRate)
def composition   = { f, g, x -> return f(g(x)) }
def calcNetPrice = composition.curry(calcTax, calcDiscountedPrice)
//  now calculate net prices
def netPrice = calcNetPrice(bk.price)
println "netPrice: ${netPrice}"		// netPrice: 26.325

The closure rMultiply is a partial application that adapts the binary multiplication to be a unary closure by using a constant second operand. The two book closures calcDiscountedPrice and calcTax are instances of the rMultiply closure with set values for the multiplier value. The closure calcNetPrice is the algorithm to compute the net price by first calculating the discounted price and then the sales tax on top of that. Finally, calcNetPrice is applied to the price of the book.

References:
http://www.ibm.com/developerworks/java/library/j-pg08235/index.html

Hope it helps!

Gautam Malhotra
gautam@intelligrape.com

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *