Skip to content

Instantly share code, notes, and snippets.

@liammclennan
Created September 6, 2012 10:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save liammclennan/3654718 to your computer and use it in GitHub Desktop.
Save liammclennan/3654718 to your computer and use it in GitHub Desktop.
CoffeeScript Currying

This is a function that does some currying:

add = (a,b) ->
  if not b?
    return (c) ->
      c + a
  a + b

JavaScript provides the capability to reflect on the number of arguments:

add.length

and to determine how many arguments were provided:

add = (a,b) ->
  if arguments.length < add.length
    return (c) ->
      c + a
  a + b

so it seems like it should be possible to write a function that magically returns a function that requires the right number of arguments. So I could have a function:

f = (a,b,c,d,e,f) ->
  ..

if invoked with:

f(1,2)

it should return:

(c,d,e,f) ->

anyone know how to do that?

@dtchepak
Copy link

dtchepak commented Sep 6, 2012

I haven't done JS in forever, so excuse this mess:

function add(x,y) { return x+y;}
function sum(x,y,z) { return x+y+z; }

function partialise(f) {    
    argCount = f.length;
    args = [];
    var getMore = function() {
        for (var i=0; i<arguments.length; i++) {
            args.push(arguments[i]);
        }
        if (args.length == argCount) {
            return f.apply(null, args);
        } else {
            return getMore; 
        }
    }

    return getMore;
}

console.debug(add(1,2));

console.debug(partialise(add)(1,2));
console.debug(partialise(add)(1)(2));
var addTen = partialise(add)(10);
console.debug(addTen(20));

var addFive = partialise(sum)(2,3);
console.debug(addFive(2));

Needs checking for when too many args are provided, and probably other stuff too.

@puffnfresh
Copy link

Here's a functional solution:

function curry(f) {
    return function(x) {
        var g = f.bind(null, x);
        if(g.length == 0) return g();
        if(arguments.length > 1) return curry(g).apply(null, [].slice.call(arguments, 1));
        return curry(g);
    };
}

var sum = curry(function(x, y) {
    return x + y;
});

var incr = sum(1);
console.log(incr(2));

console.log(sum(1)(2));
console.log(sum(1, 2));

var tuple4 = curry(function(a, b, c, d) {
    return [a, b, c, d];
});

console.log(tuple4(1)(2, 3, 4));
console.log(tuple4(1, 2)(3, 4));
console.log(tuple4(1, 2)(3)(4));
console.log(tuple4(1, 2, 3)(4));

@liammclennan
Copy link
Author

Thanks for both of your great solutions. bind is great for currying - I didn't know that it could do that.

@jfromaniello
Copy link

I use bind all the time but take car with two things...

  • it changes the context, first argument is the new context.
  • some browsers doesnt support it yet.

The second one is easy to fix, you have to add a chunk of code from the mdn:

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment