functional programming - Function application for curried functions in JavaScript and ES6 -
i love ecmascript 6 allows write curried functions this:
var add = x => y => z => x + y + z;
however, hate need parenthesize every argument of curried function:
add(2)(3)(5);
i want able apply curried functions multiple arguments @ once:
add(2, 3, 5);
what should do? don't care performance.
currying , application of curried functions controversial issues in javascript. in simple terms, there 2 opposing views, illustrate both briefly.
- use of separate curry function when necessary
the adaptation of concepts other languages or paradigms in principle thing. adaptation though, should done elementary means of target language. mean currying in javascript?
- curried functions called sequence of unary functions:
add3(1)(2)(3); // 6
- own functions manually curried arrows
const add3 = x => y => z => x + y + z;
- third party functions or methods curried separate curry function
- use of separate curry implementation default
there's problem proposed $
/uncurry
function:
const $ = (func, ...args) => args.reduce((f, x) => f(x), func); const sum = x => y => z => x + y + z; $(sum, 1, 2, 3); // 6 $(sum, 1, 2)(3); // 6 $(sum, 1)(2, 3); // z => x + y + z
in way uncurried functions can once applied unlimited number of arguments. subsequent calls must made unary. function promises. however, not allow application of curried functions, such javascript developers used to. of current curry implementations more flexible. here's extended implementation:
const uncurry = f => (...args) => args.reduce( (g, x) => (g = g(x), typeof g === "function" && g.length === 1 ? uncurry(g) : g), f ); const sum = uncurry(x => y => z => x + y + z); sum(1, 2, 3); // 6 sum(1, 2)(3); // 6 sum(1)(2, 3); // 6
this implementation works, if auto-uncurrying: once uncurried function produces curried function return value, returned function automatically uncurried. if prefer more control, following implementation might more appropriate.
the final uncurry implementation
const partial = arity => f => function _(...args) { return args.length < arity ? (...args_) => _(...args.concat(args_)) : f(args); }; const uncurry = arity => f => partial(arity)(args => args.reduce((g, x) => g(x), f)); const sum = uncurry(3)(x => y => z => x + y + z); sum(1, 2, 3); // 6 sum(1, 2)(3); // 6 sum(1)(2, 3); // 6
this tiny arity parameter brings desired control. think it's worth it.
a curry solution rest
what functions beyond our control , hence haven't been manually curried?
const curryn = uncurry(2)(arity => f => partial(arity)(args => f(...args))); const add = curryn(2, (x, y) => x + y); const add2 = add(2); add2(4); // 6
fortunately, able reuse partial
, keep curryn
concise. solution variadic functions or such optional parameters can curried.
bonus: "funcualizing" , currying methods
to curry methods, need transform nasty, implicit this
property in explicit parameter. turns out can reuse partial
adequate implementation once again:
const apply = uncurry(2)(arity => key => { return arity ? partial(arity + 1)(args => args[arity][key](...args.slice(0, arity))) : o => o[key](); }); apply(0, "tolowercase")("a|b|c"); // "a|b|c" apply(0, "tolowercase", "a|b|c"); // "a|b|c" apply(1, "split")("|")("a|b|c"); // ["a", "b", "c"] apply(1, "split")("|", "a|b|c"); // ["a", "b", "c"] apply(1, "split", "|", "a|b|c"); // ["a", "b", "c"] apply(2, "includes")("a")(0)("a|b|c"); // true apply(2, "includes", "a", 0, "a|b|c"); // true
in blog post currying discussed in detail.
Comments
Post a Comment