15

Groovy has a concept that it calls 'currying'. Here's an example from their wiki:

def divide = { a, b -> a / b }

def halver = divide.rcurry(2)

assert halver(8) == 4

My understanding of what's going on here is that the right hand argument of divide is being bound to the value 2. This seems like a form of partial application.

The term currying is usually used to mean transforming a function that takes a series of arguments into a function that only takes one argument and returns another function. For example here is the type of the curry function in Haskell:

curry :: ((a, b) -> c) -> (a -> (b -> c))

For people who haven't used Haskell a, b and c are all generic parameters. curry takes a function with two arguments, and returns a function that takes a and returns a function from b to c. I've added an extra pair of brackets to the type to make this more clear.

Have I misunderstood what's going on in the groovy example or is it merely misnamed partial application? Or does it in fact do both: that is to say convert divide into a curried function and then partially apply 2 to this new function.

Richard Warburton
  • 1,042
  • 2
  • 9
  • 14
  • 1
    for those that don't speak haskell http://msmvps.com/blogs/jon_skeet/archive/2012/01/30/currying-vs-partial-function-application.aspx – jk. Jun 14 '12 at 15:26

4 Answers4

14

Groovy's implementation of curry does not actually curry at any point, even behind the scenes. It is essentially identical to partial application.

The curry, rcurry and ncurry methods return a CurriedClosure object that holds the bound arguments. It also has a method getUncurriedArguments (misnamed—you curry functions, not arguments) which returns the composition of the arguments passed to it with the bound arguments.

When a closure gets called, it ultimately calls the invokeMethod method of MetaClassImpl, which explicitly checks to see if the calling object is an instance of CurriedClosure. If so, it uses the aforementioned getUncurriedArguments to compose the full array of arguments to apply:

if (objectClass == CurriedClosure.class) {
    // ...
    final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
    // [Ed: Yes, you read that right, curried = uncurried. :) ]
    // ...
    return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}

Based on the confusing and somewhat inconsistent nomenclature above, I suspect that whoever wrote this has a good conceptual understanding, but was perhaps a little rushed and—like many smart people—conflated currying with partial application. This is understandable (see Paul King's answer), if a little unfortunate; it will be difficult to correct this without breaking backwards compatibility.

One solution I've suggested is to overload the curry method such that when no arguments are passed it does real currying, and deprecate calling the method with arguments in favour of a new partial function. This might seem a little strange, but it would maximise backwards compatibility—since there's no reason to use partial application with zero arguments—while avoiding the (IMHO) uglier situation of having a new, differently-named function for proper currying while the function actually named curry does something different and confusingly similar.

It goes without saying that the result of calling curry is completely different from actual currying. If it really curried the function, you would be able to write:

def add = { x, y -> x + y }
def addCurried = add.curry()   // should work like { x -> { y -> x + y } }
def add1 = addCurried(1)       // should work like { y -> 1 + y }
assert add1(1) == 2 

…and it would work, because addCurried should work like { x -> { y -> x + y } }. Instead it throws a runtime exception and you die a little inside.

Jordan Gray
  • 243
  • 1
  • 6
  • 1
    I think rcurry and ncurry on functions with arguments >2 demonstrate that this really is just partial application not currying – jk. Jun 14 '12 at 15:35
  • @jk In fact, it is demonstrable on functions with arguments == 2, as I note at the end. :) – Jordan Gray Jun 14 '12 at 16:16
  • Whats the purpose of having a curried function (line 2 last example)? Isn't it to pass in arguments? – matcauthon Jun 14 '12 at 16:29
  • 3
    @matcauthon Strictly speaking, the "purpose" of currying is to transform a function with many arguments into a nested chain of functions with one argument each. I think what you're asking for is a practical reason you'd **want** to use currying, which is a bit tougher to justify in Groovy than in e.g. LISP or Haskell. The point is, what you probably want to use most of the time is partial application, not currying. – Jordan Gray Jun 14 '12 at 17:59
  • 5
    +1 for `and you die a little inside` – Thomas Eding Jun 14 '12 at 22:44
  • 1
    Wow, I understand currying much better after reading your answer: +1 and thanks! Specific to the question, I like that you said, "conflated currying with partial application." – GlenPeterson Mar 07 '13 at 04:42
  • Groovy has never been too concerned about using the same vocabulary as the rest of the programming community. Groovy's SpringSource spokesperson says: "[Changing the naming of what people are used to is painful for everybody. Groovy is for pragmatic people more than for language theorists.](http://groovy.329449.n5.nabble.com/Closures-closures-and-lambda-functions-tt5573493.html#a5573628)". – Vorg van Geir Apr 03 '13 at 13:58
  • @VorgvanGeir I approve of language designers making pragmatic decisions in accordance with the principle of least surprise. In this particular case, there's a conflict between expected semantics and inter-version consistency: the current name is awkward to everyone who knows what currying and partial application are, but changing the names now will annoy people familiar with the existing implementation. I think my suggestion above is a decent trade-off, but it depends how you prioritise those concerns. – Jordan Gray Apr 04 '13 at 14:30
3

I think it is clear that groovy curry is actually partial application when considering functions with more than two arguments. consider

f :: (a,b,c) -> d

its curried form would be

fcurried :: a -> b -> c -> d

however groovy's curry will return something equivalent to (assuming called with 1 argument x)

fgroovy :: (b,c) -> d 

which will call f with the value of a fixed to x

i.e. while groovy's curry can return functions with N-1 arguments, curried functions properly only ever have 1 argument, therefore groovy cannot be currying with curry

jk.
  • 10,216
  • 1
  • 33
  • 43
2

Groovy borrowed the naming of its curry methods from numerous other non-pure FP languages which also use similar naming for partial application - perhaps unfortunate for such FP-centric functionality. There are several "real" currying implementations being proposed for inclusion in Groovy. A good thread to start reading about them is here:

http://groovy.markmail.org/thread/c4ycxdzm3ack6xxb

The existing functionality will remain in some form and backwards compatibility will be taken into consideration when making a call on what to name the new methods etc. - so I can't say at this stage what the final naming of the new/old methods will be. Probably a compromise on the naming but we'll see.

For most OO programmers the distinction between the two terms (currying and partial application) is arguably largely academic; however, once you are used to them (and whoever will maintain your code is trained to read this style of coding) then point-free or tacit style programming (which "real" currying supports) allows certain kinds of algorithms to be expressed more compactly and in some cases more elegantly. There is obviously some "beauty lies in the eyes of the beholder" here but having the ability to support both styles is in keeping with Groovy's nature (OO/FP, static/dynamic, classes/scripts etc.).

Paul King
  • 121
  • 1
1

Given this defintion found at IBM:

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.

halver is your new (curried) function (or closure), that now takes just one parameter. Calling halver(10) would result in 5.

Therefor it transforms a function with n arguments in a function with n-1 arguments. The same is said by your haskell example what curry does.

matcauthon
  • 1,221
  • 1
  • 10
  • 18
  • 4
    IBM's definition is incorrect. What they define as currying is actually partial function application, which binds (fixes) arguments of a function to make a function with smaller arity. Currying transforms a function that takes multiple arguments into a chain of functions that each take one argument. – Jordan Gray Jun 14 '12 at 15:02
  • 1
    In the definiton of wikipedia is the same as from IBM: _In mathematics and computer science, currying is the technique of transforming a function that takes multiple arguments (or an n-tuple of arguments) in such a way that it can be called as a chain of functions each with a single argument (partial application)._ Groovy does transform a function (with two arguments) with the `rcurry` function (that takes one argument) into a function (with now only one argument). I chained the curry function with a argument to my base function to get my resulting function. – matcauthon Jun 14 '12 at 15:20
  • 3
    nope the wikipedia definition is different - the partial application is when you call the curried function - not when you define it which is what groovy does – jk. Jun 14 '12 at 15:33
  • 6
    @jk is correct. Read the Wikipedia explanation again and you will see that what gets returned is a chain of functions with one argument each, not one function with `n - 1` arguments. See the example at the end of my answer; also see later in the article for more on the distinction being made. http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application – Jordan Gray Jun 14 '12 at 16:14
  • Hm. Ok. But where is the practical difference between those two. It seems to be only theoretical nature. – matcauthon Jun 14 '12 at 16:19
  • 4
    It's very significant, trust me. Again, the code at the end of my answer demonstrates how a correct implementation would work; it would take no arguments, for one thing. The current implementation should really be named e.g. `partial`. – Jordan Gray Jun 14 '12 at 16:23