3 ms·
It specifies how many arguments the returned function should take; in my implementation, it defaults to 1 (so you can use it like "but"), but accepts other valu
by aaronem 12y ago
It specifies how many arguments the returned function should take; in my implementation, it defaults to 1 (so you can use it like "but"), but accepts other values (so you can use it like "butt").
The reason why it's necessary to specify how many arguments are of interest is because
Of course, since this is just common or garden partial application in a language with first-class functions and a liberal attitude toward signatures, it could be trivially generalized thus:
function partial(fun) {
var applied = Array.prototype.slice.call(arguments, 1);
return function() {
var args = applied
// clone the already applied args, so we don't mistakenly modify when we...
.slice()
// ...tack on the args we received in this function's call
.concat(Array.prototype.slice.call(arguments));
return fun.apply(this, args);
};
}
var addThreeNumbers = function(a, b, c) {
return a + b + c;
};
var onePlusTheseTwo = partial(addThreeNumbers, 1);
var threePlusThisOne = partial(onePlusTheseTwo, 2);
assert(addThreeNumbers(1, 2, 3) === 6);
assert(onePlusTheseTwo(2, 3) === 6);
assert(threePlusThisOne(3) === 6);
// -> all true
It only looks like wizardry if you're not used to dealing with higher-order functions, wherein I think is meant to lie the joke, if any.
- escape_goat 12y agoI don't encounter higher-order functions very often, and I certainly am not mentally flexible with them. Nonetheless, I have heard of partial application, yes. I understood what the count parameter was doing. What I was having trouble understanding was why it was being used; specifically, why 'but' would have a strict arity of one in the first place, and why a second function (specifying arity) would be necessary. It doesn't follow very clearly from the examples given at all. edit: ...was this whole thing actually a joke? I thought he was serious.
- aaronem 12y agoOh! Sorry, no, that's because ECMAScript (Javascript)'s historical baggage and lax attitude toward arity produce a combinatorial explosion of stupidity. See, you can't just ['1', '2', '3'].map(parseInt) because: 0) All Javascript functions are variadic; the signature specified at definition time is largely advisory, and has semantic meaning only in that the language will automatically declare and bind named arguments. Arguments named in a function's signature, but not passed at call time, are undefined; arguments not named in a function's signature, but passed at call time, are not automatically bound to named variables, but can be accessed via the arguments binding, which is a unique object magically bound within a function's scope, but which will be overridden by a named argument "arguments" if one exists in the signature, and 1) Array.map and friends pass their callbacks three arguments: the value of the element, the index of the element in the array being mapped over, and a reference to the entire array being mapped over, and 2) Number.parseInt requires one argument, the value to cast to integer, and accepts an optional second argument, specifying a radix between 2 and 36 inclusive. So our naïve mapping above expands to the following series of calls: parseInt('1', 0, ['1', '2', '3']); // -> 1 parseInt('2', 1, ['1', '2', '3']); // -> NaN parseInt('3', 2, ['1', '2', '3']); // -> NaN tl;dr: None of this would be necessary in a language whose collection methods did sane things. Since Javascript is not such a language, this is what we have to do. ...I'm not actually sure this whole thing was a joke, but it reads to me a little like it might've been written with the sort of smirk you tend to see academic FP purists directing at industry engineers.