An interesting question,
I have never seen a partial functional application like that, I am used to see something more like
function partial2(f, ...args) { return function() { return f.apply(this, args.concat(...arguments)); }; } console.log(partial2(foo, 1, 2)(3,4)); // => foo: 1, 2, 3, 4
Where you create once the partial application, and that's it. To me, that is the more canonical way.
Your code is in a way more flexible and fun. The only thing I can provide is to note that Array.push
returns the new count elements, and Array.length
provides the current count of elements. This means you could just skip the request of argv.length
and directly work with the return value of argv.push(...args)
function partial3(f) { const argc = f.length, argv = []; return function partialFunction(...args) { return argv.push(...args) >= argc ? f(...argv) : partialFunction; }; }
And actually, the caching of argc
seems a bit overkill, you only use f.length
once.
function partial3(f) { const argv = []; return function partialFunction(...args) { return argv.push(...args) >= f.length ? f(...argv) : partialFunction; }; }
Final thought, this might need some more fiddling.
const myPartial = partial3(foo)(1, 2, 3); console.log( myPartial('a') ); console.log( myPartial('b') ); console.log( myPartial('c') );
The expectation of a partial is that this should return
foo: 1, 2, 3, a foo: 1, 2, 3, b foo: 1, 2, 3, c
but it returns
foo: 1, 2, 3, a foo: 1, 2, 3, a foo: 1, 2, 3, a
because the partial function keeps too much state...
Belows is a snippet with the different functions and some tests;
function partial(fn) { const argc = fn.length; const argv = [] return function part(...args) { argv.push(...args); return argv.length >= argc ? fn(...argv) : part; } } function partial2(f, ...args) { return function() { return f.apply(this, args.concat(...arguments)); }; } function partial3(f) { const argc = f.length, argv = []; return function partialFunction(...args) { return argv.push(...args) >= argc ? f(...argv) : partialFunction; }; } function foo(a, b, c, d) { return `foo: ${a}, ${b}, ${c}, ${d}`; } console.log( partial(foo)(1, 2, 3, 4) ); // => foo: 1, 2, 3, 4 console.log( partial(foo)(1, 2)(3, 4) ); // => foo: 1, 2, 3, 4 console.log( partial(foo)(1, 2)(3)(4) ); // => foo: 1, 2, 3, 4 console.log( partial(foo)(1)(2)(3)(4) ); // => foo: 1, 2, 3, 4 console.log( partial(foo)()(1, 2)()(3)()(4) ); // => foo: 1, 2, 3, 4 console.log( partial2(foo, 1, 2)(3,4) ); // => foo: 1, 2, 3, 4 console.log( partial3(foo)(1, 2, 3, 4) ); // => foo: 1, 2, 3, 4 console.log( partial3(foo)(1, 2)(3, 4) ); // => foo: 1, 2, 3, 4 console.log( partial3(foo)(1, 2)(3)(4) ); // => foo: 1, 2, 3, 4 console.log( partial3(foo)(1)(2)(3)(4) ); // => foo: 1, 2, 3, 4 console.log( partial3(foo)()(1, 2)()(3)()(4) ); // => foo: 1, 2, 3, 4 const myPartial = partial3(foo)(1, 2, 3); console.log( myPartial('a') ); console.log( myPartial('b') ); console.log( myPartial('c') );