Currying is about turning/representing a function which takes n inputs into n functions that each take 1 input. Partial application is about fixing some of the inputs to a function.
The motivation for partial application is primarily that it makes it easier to write higher order function libraries. For instance the algorithms in C++ STL all largely take predicates or unary functions, bind1st allows the library user to hook in non unary functions with a value bound. The library writer therfore does not need to provide overloaded functions for all algorithms that take unary functions to provide binary versions
Currying itself is useful because it gives you partial application anywhere you want it for free i.e. you no longer need a function like bind1st
to partially apply.
With curried functions you get easier reuse of more abstract functions, since you get to specialize. Let's say that you have an adding function
add x y = x + y
and that you want to add 2 to every member of a list. In Haskell you would do this:
map (add 2) [1, 2, 3] -- gives [3, 4, 5]
-- actually one could just do: map (2+) [1, 2, 3], but that may be Haskell specific
Here the syntax is lighter than if you had to create a function add2
add2 y = add 2 y
map add2 [1, 2, 3]
or if you had to make an anonymous lambda function:
map (\y -> 2 + y) [1, 2, 3]
It also allows you to abstract away from different implementations. Let's say you had two lookup functions. One from a list of key/value pairs and a key to a value and another from a map from keys to values and a key to a value, like this:
lookup1 :: [(Key, Value)] -> Key -> Value -- or perhaps it should be Maybe Value
lookup2 :: Map Key Value -> Key -> Value
Then you could make a function that accepted a lookup function from Key to Value. You could pass it any of the above lookup function, partially applied with either a list or a map, respectively:
myFunc :: (Key -> Value) -> .....
In conclusion: currying is good, because it lets you specialize/partially apply functions using a lightweight syntax and then pass these partially applied functions around to higher order function such as map
or filter
. Higher order functions (which take functions as parameters or yield them as results) are the bread and butter of functional programming, and currying and partially applied functions enable higher order functions to be used much more effectively and concisely.
Best Answer
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
andncurry
methods return aCurriedClosure
object that holds the bound arguments. It also has a methodgetUncurriedArguments
(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 ofMetaClassImpl
, which explicitly checks to see if the calling object is an instance ofCurriedClosure
. If so, it uses the aforementionedgetUncurriedArguments
to compose the full array of arguments to apply: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 newpartial
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 namedcurry
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:…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.