Function.prototype.curryCall()

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Function.prototype.curryCall()

Peter Michaux
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
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Function.prototype.curryCall()

Brendan Eich-2
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
> [hidden email]
> https://mail.mozilla.org/listinfo/es4-discuss

_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss