Skip to content

Instantly share code, notes, and snippets.

@mkuklis
Last active September 7, 2021 21:39
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save mkuklis/5294248 to your computer and use it in GitHub Desktop.
Save mkuklis/5294248 to your computer and use it in GitHub Desktop.
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
Copy link

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
Copy link

marqsm commented Jan 6, 2014

Really nicely condensed.

@torgeir
Copy link

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
Copy link

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

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

@ivan-kleshnin
Copy link

@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
Copy link

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