Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
auto curry in JavaScript
function toArray(args) {
return [].slice.call(args);
}
function autocurry(fn) {
var len = fn.length;
var args = [];
return function next() {
args = args.concat(toArray(arguments));
return (args.length >= len) ?
fn.apply(this, args.splice(0)) :
next;
}
}
// usage
var add = autocurry(function (a, b, c, d) {
return a + b + c + d;
});
add(1)(2)(3)(4); // 10
var one = add(1);
one(4, 5, 6); // 16
add(2)(3, 4)(5); // 14
@casperin

This comment has been minimized.

Copy link

@casperin casperin commented Jun 3, 2013

I love this, but I believe there is an error in the function where if you call a partially applied function more than once, you get different results. Example:

var add = autocurry(function(a, b) {
  return a + b;
});

var addTwo = add( 2 );

addTwo( 3 ); // 5
addTwo( 3 ); // not a number like we'd expect, but a function
addTwo( 3 ); // 6

Or am I misunderstanding how the function is supposed to work?

Edit: The very last function in this blog post seems to work :-)

@marqsm

This comment has been minimized.

Copy link

@marqsm marqsm commented Jan 6, 2014

Really nicely condensed.

@torgeir

This comment has been minimized.

Copy link

@torgeir torgeir commented Jul 14, 2014

Here's one that passes the args state down the recursion instead of closing over it, making @casperin's example work

https://gist.github.com/torgeir/85532dcac47710d5be66

@djtriptych

This comment has been minimized.

Copy link

@djtriptych djtriptych commented Nov 27, 2014

This works too. Just re-bind the function on every application. Pretty pure curry implementation.

https://gist.github.com/djtriptych/7260910a5b32a572cfad

@ivan-kleshnin

This comment has been minimized.

Copy link

@ivan-kleshnin ivan-kleshnin commented Dec 3, 2015

@djtriptych your version does not support this reinjection:

let add = autocurryByMkuklis(function (a, b, c, d) {
  console.log(this);
  return a + b + c + d;
});

let add2 = autocurryByDjtriptych(function (a, b, c, d) {
  console.log(this);
  return a + b + c + d;
});

add(1).apply(42, [2, 3, 4]);  // `this` is 42
add2(1).apply(42, [2, 3, 4]); // `this` is null
@gund

This comment has been minimized.

Copy link

@gund gund commented Mar 26, 2019

Fixed curry function that does not store state in scope between multiple calls (also typed for up-to 2 arguments):

export function curry<A1, R>(fn: (arg1: A1) => R): (arg1: A1) => R;
export function curry<A1, A2, R>(fn: (arg1: A1, arg2: A2) => R): (arg1: A1) => (arg2: A2) => R;
export function curry<T extends (...args: any) => any>(fn: T): (...args: any[]) => any {
  return function(...firstArgs) {
    const argsLen = fn.length;
    let allArgs = [];

    return nextArgument(...firstArgs);

    function nextArgument(...args) {
      allArgs = allArgs.concat(args);
      return allArgs.length >= argsLen ? fn.apply(this, allArgs) : nextArgument;
    }
  };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment