Curried functions
const add = a => b => a + b;
How about making arrow function curry by default?
const add = a => b => a + b;
this will only works in case
add(a)(b);
But it won’t work if you do this
add(a,b);
If we could let arrow to work for both
add(a)(b) and add(a,b)
it will release the full power of functional programming and allow us to write code like in OCaml, F# or Haskell
I dislike that syntax because it makes the order of operations mysterious. I like the idea of currying but it should always be clear what is going on. A couple parentheses would make things a lot more obvious.
Too late, add(a)
already returns a + undefined
.
No reason why const add = curry((a, b) => a + b)
couldn't work though?
Arrow functions have a length property AFAIK.
Sorry I actually didn’t mean to use this for currying
const add = a => b => a + b;
This was directly copied from Mark's example, I was thinking about making the non-nested arrow functional. My idea is if you define
const add = (a,b) => a + b;
you will be able to use either add(a,b)
or add(a)(b)
If I understand your question correctly, your asking if fat arrow functions could be auto curried? I think this would be great, but anything using ...rest arguments could never be curried without finalization.
On 10/15/2015 12:58, Yongxu Ren wrote:
Sorry I actually didn’t mean to use this for currying
const add = a => b => a + b;
This was directly copied from Mark's example, I was thinking about making the non-nested arrow functional. My idea is if you define
const add = (a,b) => a + b;
you will be able to use either
add(a,b)
oradd(a)(b)
Alexander's point still stands. This would break compatibility, which makes it a non-starter. It also becomes dubious with variable numbers of parameters.
Waldemar
Jeremy, I think you were talking about are cases like this:
let add = (x,y,...z) => x+y+Math.max(z);
Since rested argument always has to be the last parameter, I guess this should’t be a big problem if we can interpret this case as:
//regular function and the rested argument are not curried by default
let add = (x,y) => function(...z){
return x+y+Math.max(z);
};
As long as we express it consistently, this shouldn’t be a problem.
Also, I do not believe this will be a problem:
Too late,
add(a)
already returnsa + undefined
.
First, I do not think anyone will ever intended to write code like this,
Second, if someone accidentally returned a function instead of an object, or a different function, it should be very obvious and can be very easily debugged.
It's trivially simply to write a function currify
which essentially does
what your proprosed curry
keyword does.
function currify(f) {
return function _currify(flen, _f) {
return (...args) => {
var remaining = flen - args.length;
return remaining <= 0 ?
_f(...args) :
_currify(remaining, (...args2) => _f(...args, ...args2));
};
}(f.length, f);
}
function add(a, b, c) { return a + b + c; }
var _add = currify(add);
console.log(_add(1)(2)(3));
console.log(_add(1, 2)(3));
console.log(_add(1)(2, 3));
console.log(_add(1, 2, 3));
-- Bob
I also prefer explicit currying and partial application, since it's easier to reason about types. I would rather not deal with transparent, keyword-only currying, since it can eventually become hard to debug because it can get confusing as to how many parameters are left before application. It's especially the case with dynamically typed languages.
2015-10-15 22:20 GMT+02:00 Yongxu Ren <renyongxu at gmail.com>:
First, I do not think anyone will ever intended to write code like this,
It's a wrong assumption - tons of library code depends on some argument being null or undefined.
function ajax(url, options) { options = options || defaultOptions; ... }
And in user code it can be called:
ajax('menu.html'); ajax('menu.html', null); ajax('menu.html', undefined);
BTW - I think ES2016 needs some way to curry function without binding
this
. Function.prototype.curry or something like that.
An npm package (not mine): npm.im/curry
Another simple implementation, ES3-compatible:
function curry(f) {
function curried() {
if (arguments.length >= f.length) {
return f.apply(this, arguments);
} else {
var args = []
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
return function () {
var rest = args.slice();
for (var i = 0; i < arguments.length; i++) {
rest.push(arguments[i]);
}
return curried.apply(this, rest);
}
}
}
Object.defineProperty(curried, "length",
Object.getOwnPropertyDescriptor(f, "length"));
return curried;
}
I don't need it often enough to want a standard library feature, but it's
an easy function to make. And it does exactly what you want it to: curry a
function without binding this
. If you want to make it a method decorator
as well, you can use this (also ES3-compatible):
function helper(f) {
function curried() {
if (arguments.length >= f.length) {
return f.apply(this, arguments);
} else {
var args = []
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
return function () {
var rest = args.slice();
for (var i = 0; i < arguments.length; i++) {
rest.push(arguments[i]);
}
return curried.apply(this, rest);
}
}
}
Object.defineProperty(curried, "length",
Object.getOwnPropertyDescriptor(f, "length"));
return curried;
}
function curry(target, prop, desc) {
if (typeof target === "function") {
// called on function
return helper(target);
} else {
// called as decorator
desc.value = helper(desc.value);
}
}
We can reverse this argument - why we needed Function.prototype.bind? It's quite easy to polyfill (especially if you have Reflect.construct for edge case of constructor or use eval for ES3/5 compatible implementation). There were hundreds libraries providing .bind.
Returning threads about partially applied function without writing boilerplate code or using external library are good argument to consider implementing it into language.
And in my opinion method is more readable than function.
Michał, thanks for pointing that out. Yes, optional options as the last optional parameter does exist, in multiple libraries. But I is there really existed any library that using arrow function like this? I doubt it.
I think arrow function should only be used for lambda expression, callback and short in block function. It does cause incompatibility if anyone used arrow function for API interface, but doing that is anti-pattern.
Curry function are often used in iterations, a slow polyfill will defeat the purpose. Considering this case:
map (add 1) [1..100000]
I think native syntax support for curry will be a good thing, it can be used for JIT. However, javascript already too big, so why not just let existing syntax to do the work?
Maybe it belongs on the Function prototype, something like Function.prototype.curry. To me, having Curry built into the language would be beneficial especially with the large push that is being seen toward Functional development in JavaScript.
The main reason I don't use it is because I have bad experiences with transparent currying in dynamic languages. It'll be one of those things I almost never have the use case for. Kinda like SIMD and Math.imul. YMMV
Well, as I see it, there is nothing that currently could be done with to this if what you desire is to make it automatic. What we could add are various ways of manually doing this, either as syntax or as library extensions. And then comes the question of which way and what exactly.
Are you talking about pure currying, that is, taking a multiple parameter function and turning if into a series of it's arity many single argument functions, i.e: (a,b,c)=>a+b+c --> a=>b=>c=>a+b+c ?
Are you talking about partial application,i.e: (a,b,c)=>a+b+c --> (a,b,c..._)=>a+b+c
OR (a,b)=>(c,..._)=>a+b+c
OR a=>(b,c,..._)=>a+b+c
OR a=>b=>(c,..._)=>a+b+c
And where any zero argument applications return the same function?
Is it currying or partial application you want? How do you handle functions that take rest parameters, optional parameters, true variadric functions like e.g. sum that is theoretically zero to infinity arity? or whose arity with to partial application (and not the formal functionobject.length arity) is dependent on the contents of those arguments? How do you handle this value? How do you handle arguments object? How do you handle named autorecursion? Do you want to be able to do this for constructors as well? How about getters and setters? Generators? How do you handle extremely high argument counts? How do you handle defaults? How do you handle argumentless applications?
Automating this is in the language as it is would be a no-go for backwards compatibility reasons I would say. Possibly you could have manual currying, like what I wrote for rosettacode here: rosettacode.org/wiki/Currying#Generic_currying_for_ECMAScript_2015.28ES6.29
Note the several caveats in that code. And sure, you could add syntax for it instead of using a function like I do there, but it's still the same explicit action, so would syntax really help in any way? And for several cases you'd actually have to make a decision and stick to it, or implement all the alternatives. Just see how I had to deal with rest arguments there, because without two different versions, I would have to choose either to handle rest arguments always with a separate application, or never. If you want partial application, that's slightly different in a few ways, but not notably harder.
How about we use a different approach?
Instead of allowing a(b)(c)
for let a = (b,c) => b+c;
,
Maybe we can use a(b,c)
for let a = b => c => b + c
?
On 17 Oct 2015 04:48, "Yongxu Ren" <renyongxu at gmail.com> wrote:
How about we use a different approach?
Instead of allowing
a(b)(c)
forlet a = (b,c) => b+c;
,Maybe we can use
a(b,c)
forlet a = b => c => b + c
?
Would that do any of the useful stuff you could reasonably want either currying or partial application for, though? I mean the main use is that it allows us to do let d=a(b); ... d(c); And I don't really see how your desugaring a single multiple argument application into several single parameter curried functions allows that usefulness.
It's the multiple applications to fill single parameter list thing that is the most useful part of it, mostly as it allows caching the closure at any step for reuse, not single application to fill multiple sequential single parameter lists. Also, consider rest parameters, defaults etc. and whether doing what you want for the simple example case would have weird or possibly ambiguous meaning. Also, what happens to this value if the functions are old style and not new style?
Here's what I see as what's being proposed here. Correct me if I'm wrong.
Function currying means it can be partially applied when only given some of its arguments. For example:
var add = _.curry(function (a, b, c) { return a + b + c })
add(1)(2)(3) === 6
add(1, 2)(3) === 6
add(1)(2, 3) === 6
add(1, 2, 3) === 6
var add3 = add(3)
add3(2, 1) === 6
add3(2)(1) === 6
var add5 = add(3, 2)
add5(1) === 6
That's exactly the behavior in Underscore's and Lodash's _.curry()
.
And that's exactly what I (and most others) would expect.
As for Yongxu Ren's idea, that wouldn't be very performant, as engines
have never been made to handle very highly nested closures very well.
That's a great idea in statically typed, mostly pure functional
languages (Haskell and OCaml both do that), but in languages that
accept multiple arguments for a single function like Java or Python,
it's hard to optimize at all. JavaScript is no exception. It's also
cheaper to do a function length comparison than an unavoidable
IsCallable
check for each argument passed (which that would
require).
As long as the total numbers of argument and types are consistent, which are mostly true for curry functions, it should be able to easily optimized.
Also, the polyfill for curry is just way too slow.
Of course, faster is always better, and native is always (?) faster.
Having said that, with the fastest polyfill I have managed to write, given
function add(a, b, c) { return a + b + c; }
var _add = currify(add);
A call to add(1,2,3)
takes 0.016 microseconds. A call to _add(1)(2)(3)
takes 0.43 microseconds, 25 times longer. However, in the real world, it is
more common to curry the function once and then invoke the curried function
multiple times. If we do add1 = _add(1)
, then each call to add1(2)(3)
takes 0.30 microseconds, or 20 times longer. If we do add2=_add(1, 2)
,
then each call to add2(3)
takes 0.10 microseconds, or 6 times longer. In
relative terms this still seems like a large penalty, but in absolute
terms, maybe not so much.
On another topic, in terms of the approach for delivering this
functionality, the best solution would seem to be to put this in a new
standard library. If we want to instead extend the language syntax, of
course we cannot introduce a new curry
keyword, but maybe we can take a
hint from the *
used for generators and do something like
function #add(a, b, c) { }
function :add(a, b, c) { }
function ()add(a, b, c) { }
function add((a, b, c)) { }
etc. etc.
-- Bob
Something like curry-this would be nice to have, so we could do something like:
const add = (
(a, b, c) => a + b + c
)::curry();
It would be really cool to have syntax to curry functions built into the languages. Something like...
curry function add(a, b) { return a + b; } add(2)(3); // 5