Currying Schonfinkelling

It's really just called currying, but that's not a WikiName. Currying is a property of functions discovered by Moses Schoenfinkel in 1924. However at the time, HaskellCurry got most of the good press about FunctionalProgramming so it was named after him. The term itself was supposedly invented by ChristopherStrachey.

If you read the FAQ, you'll see that the property described (the isomorphism of AxB->C with A->B->C) was a "well known fact" well before Schoenfinkel and Curry. Their contributions were apparently in the area of the EssAndKayCombinators.

Currying is the concept that functions of multiple arguments are really just HigherOrderFunctions which take one argument and return functions. In a sort of Javaish syntax, Here are examples:

 // two arg version
 int sum(int a, int b) { return (a+b); }

// one arg version int sum(int a) { return int sum1(int b) { return (a+b); } }

// optimised multiplication int mult(int a, int b) { select (a) { case -1: return int neg(int b) { return -b; } case 0: return int zero(int b) { return 0; } case 1: return int ident(int b){ return b; } default: return int std(int b) { return a*b; } } }

In fact you could write that in legitimate JavaScript:

 // two arg version
 var sum = function(a, b) { return (a+b); }

// one arg version var sum = function(a) { return function(b) { return (a+b); }} // Which would be used as, e.g., var plusfour = sum(4); var six = plusfour(2); var alsosix = sum(4)(2);

// optimised multiplication function mult(a) { switch(a) { case -1: return function(b) { return -b; } case 0: return function(b) { return 0; } case 1: return function(b) { return b; } default: return function(b) { return a*b; } } } var answer = mult(6)(9);

"And why would I care?" <-- That's what I was thinking when I read this. ;->

But now I see an application of this:

This idea is used quite heavily in the SynthesisOs. You see, if the value of "a" is known at one point in the run, and we intend to add lots of "b" values to it, then SynthesisOs calls "sum(int a)", which generates the code to do "sum1(int b)" -- where 'a' is a constant. This is called PartialEvaluation. It gives SynthesisOs a substantial performance boost, as it can do code optimization based on the value of 'a'. Like, if 'a' happens to be zero, it generates/returns the code "int sum1(int b) { return b; }", optimizing the addition right out. Likewise, if 'a' is one, it generates/returns the function "int sum1(int b) { return ++b; }". Fast. Very fast. (See the paper on SynthesisOs. It claims "10 times faster than Unix.") -- JeffGrigg

"And why would I care?"

Because it makes programming much easier and programs much easier to understand. For example, here's a piece of Haskell code to double all elements of a list:

 double aList = map (* 2) aList
That is, to double a list, apply "* 2" to each element -- the * operator has been curried.

And this definition can itself be curried, so that:

 double = map (* 2)
-- NatPryce

Is that really that much easier to understand than

 @alist = map {$_ * 2} @alist;
...But that code does not define a new function.

But it does define a PerlLanguage block, which, if I understand correctly, is a code object with a lot of the same properties as a scheme closure.

(No, it doesn't; it defines an array, "@alist". But it does so in terms of the block '{$_ * 2}', which is in effect an anonymous function)

To elaborate:

 double = map (* 2)

list1 = [1, 2, 3, 4, 5] list2 = [10, 20, 30, 40, 50]

double list1 >[2, 4, 6, 8, 10]

double list2 >[20, 40, 60, 80, 100]

In the FortranLanguage this particular (and many similar problems) can be reduced to

A = A * 2
where A is a arbitrarily shaped array. But that is not the point.

You can curry objects too.

For example, instead of sending

 window drawCircleAt: 10@10 Colour: #red
 window drawCircleAt: 20@20 Colour: #red
 window drawCircleAt: 30@30 Colour: #red
you can curry away the Colour argument, making a new object called a pen.

 pen := window pen colour: #red
 pen drawCircleAt: 10@10
 pen drawCircleAt: 20@20
 pen drawCircleAt: 30@30
CurriedObject is a generalisation of a number of other patterns, like AbstractSession?, IteratorPattern, as well as pens in graphics systems.

-- JamesNoble

Given historical precedent, AbstractSession?, IteratorPattern, and graphics system pens are more like specialisations of, or at least attempts to emulate aspects of, curried objects. Other patterns seem to be trying to hark back to currying; for example, is VisitorPattern much more than curried traversal? I sometimes get the feeling that one of the things that has been forgotten (or at least, was forgotten: there seems to be some attempt to recapture the idea in recent times) by the designers of OO languages is that functions are objects, too. A lot of DesignPatterns - VisitorPattern, StrategyPattern, DecoratorPattern, AdapterPattern, ... - seem like techniques for transporting functions from one object to another. Currying recognises that functions can be constructed in a series of steps.

Thank you. There is quite a lot of information on this wiki about this. One starting point is the work of ThomasKuehne in FunctionalPatternSystemForObjectOrientedDesign. There is also the work FC++ (FunctoidsInCpp), an attempt to implement in CeePlusPlus a lot of things found in HaskellLanguage. -- JohnFletcher


EditText of this page (last edited May 6, 2012) or FindPage with title or text search