Higher-Order Functions Are Just Shape Adapters
What a higher-order function actually is, why JavaScript functions accept any number of arguments, and how to build your own shape-adapting utility.
"Higher-order function" sounds like it needs a computer science degree to unpack. It doesn't.
A higher-order function is just a function that takes another function as input, or gives one back as output, or both. That's the entire definition. Once you have that, a huge amount of "advanced" functional programming turns out to be a small, learnable pattern repeated over and over.
A Real Bug This Solves
Here's a classic JavaScript mistake:
['1', '2', '3'].map(parseInt);
// [1, NaN, NaN]Looks harmless. It isn't, because .map() calls its callback with three arguments: the value, the index, and the whole array. parseInt happens to accept a second argument too, a radix, so index 1 and 2 get used as the base to parse in, silently producing garbage.
The function's shape didn't match what .map() was handing it. The last post called this exact mismatch out as the reason shape matters.
Building the Fix
The fix is a small higher-order function that forces any function down to a single argument, no matter how many it actually receives:
function unary(fn) {
return function (arg) {
return fn(arg);
};
}
['1', '2', '3'].map(unary(parseInt));
// [1, 2, 3]unary takes a function in, and hands back a new function. That returned function only ever forwards one argument, no matter how many .map() tries to pass it. unary itself is the higher-order function here, since it operates on a function rather than a plain value.
The same idea works for exactly two inputs:
function binary(fn) {
return function (arg1, arg2) {
return fn(arg1, arg2);
};
}Useful anywhere a callback needs precisely two arguments and nothing more, a reducer combining two running totals, say, without extra arguments leaking in from whatever's calling it.
Why This Works at All: JavaScript Functions Are Variadic
Both utilities lean on something worth naming directly: JavaScript functions are variadic. A function declared with two parameters can be called with four, or with zero, and JavaScript won't complain either way. Extra arguments are silently ignored; missing ones just come through as undefined.
That's exactly why unary works. Wrapping a function so it only ever forwards one argument doesn't need permission from the original function, JavaScript never enforced a fixed number of arguments to begin with.
The Real Skill Is Building Your Own
unary and binary solve two common mismatches. Real code runs into shapes neither one covers.
The actual skill worth developing isn't memorizing a fixed set of adapters. It's recognizing when two pieces don't fit, and writing a small function that makes them fit. That's all unary and binary are: a function wrapped around another function, changing nothing about what it computes, only how many arguments make it through.
Once that clicks, reading someone else's functional utility library stops feeling like decoding a foreign language. It's mostly this same move, over and over, with a different name for each specific shape problem. The next post looks at a shape mismatch that isn't about the number of arguments at all, it's about their order.
Keep reading