Coder Profile - Show off your skills, get a coder profile.
 
 
 
Currying in JavaScript: Fun for the Whole Family!
Programming
As I've said before, I'm quite partial to JavaScript. Lately, I've been reading about currying functions, so let's see if currying can be done in JavaScript.

The begs the question, What is currying? Currying is a technique to transform a function that takes some number of arguments to a function that takes fewer. The process was named after the logician Haskell Curry. The goal is to get something that works like this:
Code :: Figure 1 Copy / Restore
  1. function add(a, b)
  2. {
  3.      return a + b;
  4. }
  5.  
  6. alert(add(3, 4)); // 7
  7.  
  8. var add_3 = add(3);
  9.  
  10. alert(typeof add_3); // function
  11. alert(add_3(4)); // 7
When we pass fewer than the required number of arguments, it returns a function that takes the remaining arguments. Once we pass the correct number of parameters, it evaluates the function.

Before possibly reinventing the wheel, I looked online to see if anyone had done this. While there are plenty of JavaScript functions that claim to curry, they all get it wrong. They do something like this (using the same add from above):
Code :: Figure 2 Copy / Restore
  1. var add_3 = curry(add, 3);
  2.  
  3. alert(add_3(4)); // 7
  4. alert(typeof add(3)); // number
They do get the add_3 function in the end, but all they do is create a new function with fewer arguments. Any calls to add will still behave like any other JavaScript function with too few arguments; the remaining arguments will be undefined. The add_3 function (both times) is called a partial function.

So how do we do proper currying in JavaScript? Here's what I did. It takes three steps.

First, we need a way to change a function's arity. Arity is the number of parameters a function accepts. This may not seem directly relevant, but trust me:
Code :: Figure 3: Function::toArity Copy / Restore
  1. Function.prototype.toArity = function (n)
  2. {
  3.      var func = this;
  4.      var parmString = '';
  5.      var funcString = '';
  6.      var i;
  7.  
  8.      if (n == func.length)
  9.      {
  10.          return func;
  11.      }
  12.  
  13.      if (n == 0)
  14.      {
  15.          return function ()
  16.          {
  17.              return func.apply(this, arguments);
  18.          };
  19.      }
  20.  
  21.      for (i = 0; i < n; ++i)
  22.      {
  23.          parmString += 'a' + i;
  24.  
  25.          if (i < n - 1)
  26.          {
  27.              parmString += ',';
  28.          }
  29.      }
  30.  
  31.      funcString = '(function (' + parmString + ') { return func.apply(this, arguments); })';
  32.      return eval(funcString);
  33. };
This function looks complicated, but it's not really. The basic idea is to wrap the function call in another function of the desired arity. They only way to do this in JavaScript is to create the function at runtime with eval. I know most people (myself included) advocate against eval, but in this case it is truly the only way. So this function will convert something like this:
Code :: Example 4 Copy / Restore
  1. function iTake3Args(a, b, c)
  2. {
  3.      return a + b; // Ignore c
  4. }
via this call:
Code :: Example 4 (cont) Copy / Restore
  1. iTake3Args.toArity(2);
to something like this:
Code :: Example 4 (cont) Copy / Restore
  1. function anonymous(a0, a1)
  2. {
  3.      return func.apply(this, arguments);
  4. }
It may look ugly, but it works. And no-one should be printing the internals of the function anyway (they'll be calling it).

So now that we can control the arity of functions, we can generate partial functions (what all the libraries do) correctly (with the property arity). The function goes like this:
Code :: Example 5: Function::partial Copy / Restore
  1. Function.prototype.partial = function ()
  2. {
  3.      var partialArgs = Array.prototype.slice.call(arguments, 0);
  4.      var func = this;
  5.  
  6.      var retFunc = function ()
  7.      {
  8.          var args = Array.prototype.slice.call(arguments, 0);
  9.          return func.apply(this, partialArgs.concat(args));
  10.      };
  11.  
  12.      return retFunc.toArity(Math.max(0, func.length - partialArgs.length));
  13. };
There's quite a bit going on here. Why is the arguments object being passed to slice? The arguments object is only just that, an object. We need to convert it to a proper array so we can concatenate the two argument arrays in the partial function. Then the return function (with arity 0) is converted to the proper arity. The function works similarly to the other curry functions:
Code :: Example 6 Copy / Restore
  1. var add_3 = add.partial(3);
  2.  
  3. alert(add_3(4)); // 7
Now we can finally get to currying properly. Here's the function:
Code :: Example 7: Function::toCurriable Copy / Restore
  1. Function.prototype.toCurriable = function ()
  2. {
  3.      var func = this;
  4.  
  5.      var retFunc = function ()
  6.      {
  7.          if (arguments.length < func.length)
  8.          {
  9.              return func.partial.apply(func, arguments).toCurriable();
  10.          }
  11.  
  12.          return func.apply(this, arguments);
  13.      };
  14.  
  15.      return retFunc.toArity(func.length);
  16. };
If you've understood everything so far, this shouldn't be too out there. If there aren't enough arguments, a partial function will be returned. Otherwise, the function is evaluated. The return function (with arity 0) is converted to the proper arity. So finally, we can recreate our initial example (with a couple changes):
Code :: Example 8: See Example 1 Copy / Restore
  1. var add = function (a, b)
  2. {
  3.      return a + b;
  4. }.toCurriable();
  5.  
  6. alert(add(3, 4)); // 7
  7.  
  8. var add_3 = add(3);
  9.  
  10. alert(typeof add_3); // function
  11. alert(add_3(4)); // 7
Note the change to the definition of add. It has to be a function expression rather than a function definition because we want the result of toCurriable, not the original function.

This is by no means a perfect solution. While it preserves arity, it does not preserve scope. Things like:
Code :: Example 9 Copy / Restore
  1. someObj.func(3)(4);
won't work as expected, because the second function call is evaluated in global scope rather than on someObj. To get the expected result, one should program:
Code :: Example 9 (cont) Copy / Restore
  1. (someObj.func(3)).call(someObj, 4);
This evaluates both functions in the scope of someObj. I don't see any way around this ugly syntax at the moment.

Also, this solution relies on closures and eval, which means it will be memory intensive and will be slow in some browsers. I have not tested this in any browsers, only in Mozilla's Rhino, a command-line JavaScript environment. I imagine it will work in any Mozilla product. I make no claims about Internet Explorer.

I do, however, feel that this is an elegant and unobtrusive solution that has not been done before. This was a purely theoretical endeavor. True currying is definitely possible in JavaScript.

I hope someone found this useful. You can download all of the above functions in the attached JavaScript file.


Posted By neko-mangaka
Please login to rate coding articles.

Click here to register a free account with us.
Attachment
Download Download Attachment
curry.js.zip ( 0.00Mb )
NEVER open a .exe, .bat, .cmd, or other executable file since that is where viruses are likely to live. Please virus scan all files you download.
Comments
Please login to post comments.
 
neko-mangaka     Posted 53 Days Ago
 
 
closure,

I'm not sure I understand the Scheme, but I think I can answer your question.
I had to change the arity of the returned functions to allow multiple curryings.
Take a look at this example:

var dostuff = function (a, b, c) { return a + b * c; }.toCurriable();

I should be able to call dostuff in any of the following ways:

dostuff(1, 2, 3);
dostuff(1)(2, 3);
dostuff(1, 2)(3);
dostuff(1)(2)(3); // All evaluate to 7

The last one requires two curryings. For this to work, it has to know if enough
arguments are passed each time. I get the arity from the Function.length property.
If I just returned functions with no parameter list (i.e. didn't change the
arity), currying could only be done once.
 
closure     Posted 76 Days Ago
 
 
hi,
i don't quite get the point of changing the arity here.
All you need is higher order procedures and the ability for variable function
arguments. Which i believe are both present in javascript.
In scheme a generalized curry would look sth like this:
(define ((curry proc . args) . args*)
(apply proc (append args args*)))

I think something like this could well be done in javascript. As you're
allways returning a newly created function, there is no point of changing the arity
of an existing one, right?

cheers
 
neko-mangaka     Posted 137 Days Ago
 
 
That's a bit different, though. In function overloading, passing different
numbers of arguments calls different functions that happen to have the same name.
But they always return a value (which in JS might happen to be a function).

In automatic-currying, there's only one function, but if you pass fewer
arguments than expected it returns itself "with some of the arguments filled
in".

A simple system for function overloading in JS might be my next project, though.
You've intrigued me. ;)
 
VBAssassin     Posted 137 Days Ago
 
 
"where passing fewer than the required number of parameters automagically
returns another function"

Sounds like the technique called "function overloading" to me.

Kind regards,
Scott
 
neko-mangaka     Posted 137 Days Ago
 
 
Looking at some of the prototype examples, I see they're one up on my approach.
They can do something like this:

Array.prototype.get = function (n)
{
return this[n];
};

Array.prototype.getFirst = Array.prototype.get.curry(0);

[1, 2, 3].getFirst(); // 1

Prototype can curry a function down to zero-arity. Although it's a bit
outside the technical definition of currying, it's a very useful feature.
 
neko-mangaka     Posted 137 Days Ago
 
 
Again, I think I was a bit off in my terminology. You're right, there are
frameworks to curry functions. Maybe I should have said "auto-currying"; I
was going for something like Haskell, where passing fewer than the required number of
parameters automagically returns another function without the need for an explicit
bind() or curry() function.

Also, I wanted to keep the Function::length field accurate. I'm not sure how
many browsers support it, but Mozilla does.
 
VBAssassin     Posted 137 Days Ago
 
 
I quite like that article. When i first heard about currying it took me a while to
get my head round the fact that currying is usefull and not pointless lol.

Anyway you said "Before possibly reinventing the wheel, I looked online to see
if anyone had done this. While there are plenty of JavaScript functions that claim to
curry, they all get it wrong."

I suggest you look at a javascript framework called "prototype". It has
some very powefull currying functions that do work the way currying is supposed to
;-)

Some other libraries such as mootools and jQuery may also curry, but i don't
know about those libraries since i don't know those libraries so well as i do
prototype.

Kind regards,
Scott
Page 1 of 1
More Articles By This Author
Currying in JavaScript: Fun for the Whole Family!
Recently Posted "Programming" Articles
N-Queens-Series Part I (Only the fittest survive)
Currying in JavaScript: Fun for the Whole Family!
[PHP] Create A Unique Page Hits Counter
Actionscript Events
Actionscript API
Quick Threading Tutorial - C++
C++ And Me (A Love Story)
First look at C
Introduction to Pseudo Code
Integrating your website with PHP
Recently Rated "Programming" Articles
[C++] Templates
Quick Threading Tutorial - C++
Intorduction to memoization.
N-Queens-Series Part I (Only the fittest survive)
[PHP] Create A Unique Page Hits Counter
Currying in JavaScript: Fun for the Whole Family!
Actionscript Events
First look at C
if/else, switch/case and ?/: Statements In Actionscript 2.0
Actionscript API
source codes Categories articles
Browse All
Business & E-Commerce (1)
Databases (1)
Design & Creativity (1)
Internet & Web Sites (1)
Life In General (2)
Operating Systems (3)
Other (2)
Programming (48)
Security (10)
Software Development (5)
Web Development (15)
search Search Inside
Programming
 
 
Part of the MyPingle Network
Development Blog :: Make A Donation :: Contact Me
Terms & Conditions :: Privacy Policy :: Documents
Version 1.44.00
Copyright © 2007 - 2008, Scott Thompson, All Rights Reserved