3 ms·
I tweeted this yesterday: Why does Underscore.js get the order of arguments wrong? There’s a reason why it’s map(fn, l), not map(l, fn). And the reason is curr
by steadicat 16y ago
I tweeted this yesterday:
Why does Underscore.js get the order of arguments wrong? There’s a reason why it’s map(fn, l), not map(l, fn). And the reason is currying.
I find that very annoying for the kind of functional programming I tend to do. For that reason alone I started looking at Wu.js instead.
Am I missing something?
- shawndumas 16y agoI mainly use Object-Oriented Style[1]. ----- http://documentcloud.github.com/underscore/#styles http://documentcloud.github.com/underscore/#styles
- steadicat 16y agoCan you do things like var sum = curry(reduce, add); with the OO style? Am I wrong in thinking that this kind of currying is one of the fundamental building blocks of functional programming?
- shawndumas 16y agoDo you mean like this? var sum = function (a) { return _(a).reduce(function (m, n) { return m + n; }, 0); }; sum([1,2,3,4,5,6,7,8,9]); // => 45 Or am I not getting you?
- steadicat 16y agoThat's one way to do it, but you're falling back to explicitly defining a new function, rather than creating it by combining higher-order functions. Which kinda defeats the point.
- shawndumas 16y agoAll I would have to do is abstract the outer function out and call it curry (partial[1], really). var add = function (m, n) { return m + n; }, partial = function (mth, fn) { return function (l) { return _(l)[mth](fn, 0); }; }, sum = partial('reduce', add); sum([1,2,3,4,5,6,7,8,9]); // => 45 ----- [1]: http://lambda-the-ultimate.org/node/2266 http://lambda-the-ultimate.org/node/2266
- jashkenas 16y agoOrder of arguments shouldn't be a fundamental problem for currying -- libraries like Functional.js allow you to curry from the left, or to curry from the right, as you desire. However, having higher-order functions in JavaScript take their function argument in the final position is an extremely common and important pattern in JavaScript. Most libraries prefer this: call(arg, arg, function() { ... }); Instead of this (which hides relevant arguments far away from the actual call site): call(function() { ... }, arg, arg);
- steadicat 16y agoThat's a good point. However, I find it funny that you should mention another functional library as a way around the issue. Doesn't that defeat the purpose of Underscore? I have a feeling that either the authors of Underscore don't fully get functional programming, or I don't. Of course, the latter is much more likely, that's why I'm looking for someone to set me straight.
- jashkenas 16y agoFull disclosure: I'm the author. Depending on your definition, nothing in JavaScript is "fully functional programming", because then it would have to be side-effect-free, and JavaScript is very much not that language. Calling them "functional helpers" is mostly a way of distinguishing the style in which you use them, as opposed to the object-oriented versions of the same helper functions, which can be found in libraries like Prototype.js. The idea here being that you can use them in a functional style without having to extend native objects. As I mentioned above, calling "map" with the iterator as the final argument isn't a limitation here -- it's a feature. There aren't many (any) situations I've ever seen in real-world JS where you'd want to curry together a list of iterators, and then map them together across the array, all at once. And if you do want to do such a thing, you can accomplish it either like this: _.map(list, function(item) { return convert1(convert2(convert3(item))); }); Or, if you want to get fancy, take a look at "compose": http://documentcloud.github.com/underscore/#compose http://documentcloud.github.com/underscore/#compose _.map(list, _.compose(convert1, convert2, convert3));
- deleted 16y ago
- mrkurt 16y agoYou really want the order of arguments to be 'fn,list' when you're working with a language that has partial function application (currying with no special syntax, basically). In a language like Javascript where you have to resort to a curry function, there's no practical difference. A curry function implementation can actually be made to work with either argument order pretty easily. And in javascript, having the function last is relatively standard and much nicer to look at.