Curry is one of my favorite functions - it’s one of those indispensable tools that you never know about until you need it, and then in a flash you realize all of the potential applications for.
First of all, I need to give credit where credit is due. I learned about curry() while using Dojo, and was shocked to find out that MooTools’ pass() didn’t do the same thing. So special thanks to Alex Russell of Dojo and the other dude whose code I lifted and adapted for use in MooTools.
What is a Curry?
Aside from being a delicious spicy Thai mainstay, it’s also the process of wrapping a function inside another function, such that some of the inner functions’ arguments have already been defined.
Say What?
Let’s say you have a function printName, which expects lastName and firstName as arguments. To whit:
printName = function(lastName, firstName){
alert("Hello, " + firstName + " " + lastName);
}
Now let’s say you have a list of names that are in a Hash, like this:
names = $H({
'Jones': ['Barnaby','Sally','Timmy','Bridget'],
'Smith': ['Gabby', 'Kelly', 'Crabby']
});
Here’s how a curry can help:
names.each( function(firsts, lastName){
var fn = printName.curry(lastName);
firsts.each( fn );
})
Whoa.
What’s happened above is that we’ve walked through the last names object, which gives us a list of the first names (’firsts’) and a string key which is the last name (’lastName’). Next, we create a temporary function ‘fn’ that is a copy of printName, but with the first argument (lastName) already filled in. Next, we pass each of the first names in turn to the temporary function. Since the first argument that each() passes is the value of the array item (the first name), we are effectively calling printName with both the first argument (from the curry) and the second argument (from each()) filled out.
In this case, curry() helped us to avoid a potentially inelegant series of for() loops. We could even state the same code in a simpler (albeit more opaque) manner:
names.each( function(firsts, lastName){
firsts.each( printName.curry(lastName) );
});
How does it work?
Curry() takes a function’s argument list and holds it in a closure, which it returns. The big difference between my MooTools curry() and MooTools’ own pass() is support for multiple levels of curry. Once you call pass(), calling pass() again on the result won’t get you anywhere. My curry() can attach as many arguments as you want. Another difference is that pass() takes an array as it’s first argument if you want to pass multiple arguments. For curry(), just call it as if it were the target function and the args will be converted to an array for you.
Function.prototype.curry = function()
{
var method = this, args = Array.prototype.slice.call(arguments);
return function()
{
return method.apply(this, args.concat(Array.prototype.slice.call(arguments)));
};
};
Tags: abstract, advanced, mootools
[...] Un articol interesant in care autorul implementeaza o metoda Function.curry in MooTools este How about a nice, spicy curry? Din nou, acest articol este destinat celor familiari cu programarea functionala; oricum, daca cineva [...]