Function.prototype.curryCall()
# Brendan Eich (18 years ago)
That's partial application, not currying. No one has proposed its
standardization; lots of Ajax libraries implement it much as you show
below. The ones I've looked at play their own custom variations on a
theme, so wouldn't all be subsumed by a standard.
That's partial application, not currying. No one has proposed its standardization; lots of Ajax libraries implement it much as you show below. The ones I've looked at play their own custom variations on a theme, so wouldn't all be subsumed by a standard. /be On Aug 28, 2007, at 2:20 PM, Peter Michaux wrote: > Hi, > > Has JavaScript support for function currying been proposed? Maybe > there is already something like this planned? > > > Function.prototype.curryCall = function(scope) { > var args = []; > for (var i=1; i<arguments.length; i++) { > args.push(arguments[i]); > } > var f = this; > return function() { > for (var i=0; i<arguments.length; i++) { > args.push(arguments[i]); > } > return f.apply(scope, args); > } > } > > > //------------ > // Example use > > function foo(a, b, c, d) { > alert(this.name + a + b + c + d); > } > > var bert = {name:'Bert'}; > > var curriedFoo = foo.curryCall(bert, 1, 2); > > curriedFoo(3, 4); // alert says "Bert1234" > > > > > Currying is handy when attaching event handlers in a for loop since > for loops don't introduce a new scope with each iteration. > > Suppose we want to attach a click handler to each item in an HTML > list. The handler prints the position of the item in the list and also > the innerHTML of the item. One way we could write this handler... > > function handler(i) { > alert('item ' + i + ': ' + this.innerHTML); > } > > var items = document.getElementById('myList').getElementsByTagName > ('li'); > > // three ways to attach the handlers > > //---------------------------------------- > // OPTION 1: inline currying (what a mess) > > for (var i=0; i<items.length; i++) { > var item = items[i]; > item.addEventListener('click', (function(item, i) { > return function(){ > return handler.call(item, i); > } > })(item, i), false); > } > > > //---------------------------------------------- > // OPTION 2: extracted currying (a little nicer) > > function curryHandler(item, i) { > return function() { > return handler.call(item, i); > }; > } > > for (var i=0; i<items.length; i++) { > var item = items[i]; > item.addEventListener('click', curryHandler(item, i), false); > } > > > //-------------------------------------------------------- > // OPTION 3: with Function.prototype.curryCall (succinct!) > > for (var i=0; i<items.length; i++) { > var item = items[i]; > item.addEventListener('click', handler.curryCall(item, i), false); > } > > The event object will be passed as the second argument to the > handler function. > > There is precedence for other developers wanting this functionality. I > believe Prototype's Function.prototype.bind() may be the same thing as > the Function.prototype.curryCall() that I've written. The Prototype > Function.prototype.bindEventListener() will pass the event object as > the first argument to the curried function. > > Any thoughts on the utility of currying as part of JavaScript? > > Peter > _______________________________________________ > Es4-discuss mailing list > Es4-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es4-discuss
Has JavaScript support for function currying been proposed? Maybe there is already something like this planned?
Function.prototype.curryCall = function(scope) { var args = []; for (var i=1; i<arguments.length; i++) { args.push(arguments[i]); } var f = this; return function() { for (var i=0; i<arguments.length; i++) { args.push(arguments[i]); } return f.apply(scope, args); } }
//------------ // Example use
function foo(a, b, c, d) { alert(this.name + a + b + c + d); }
var bert = {name:'Bert'};
var curriedFoo = foo.curryCall(bert, 1, 2);
curriedFoo(3, 4); // alert says "Bert1234"
Currying is handy when attaching event handlers in a for loop since for loops don't introduce a new scope with each iteration.
Suppose we want to attach a click handler to each item in an HTML list. The handler prints the position of the item in the list and also the innerHTML of the item. One way we could write this handler...
function handler(i) { alert('item ' + i + ': ' + this.innerHTML); }
var items = document.getElementById('myList').getElementsByTagName('li');
// three ways to attach the handlers
//---------------------------------------- // OPTION 1: inline currying (what a mess)
for (var i=0; i<items.length; i++) { var item = items[i]; item.addEventListener('click', (function(item, i) { return function(){ return handler.call(item, i); } })(item, i), false); }
//---------------------------------------------- // OPTION 2: extracted currying (a little nicer)
function curryHandler(item, i) { return function() { return handler.call(item, i); }; }
for (var i=0; i<items.length; i++) { var item = items[i]; item.addEventListener('click', curryHandler(item, i), false); }
//-------------------------------------------------------- // OPTION 3: with Function.prototype.curryCall (succinct!)
for (var i=0; i<items.length; i++) { var item = items[i]; item.addEventListener('click', handler.curryCall(item, i), false); }
The event object will be passed as the second argument to the handler function.
There is precedence for other developers wanting this functionality. I believe Prototype's Function.prototype.bind() may be the same thing as the Function.prototype.curryCall() that I've written. The Prototype Function.prototype.bindEventListener() will pass the event object as the first argument to the curried function.
Any thoughts on the utility of currying as part of JavaScript?
Peter