I have a function in search of a name.
I've been building a new functional programming library in Javascript, and I recently added a new function that looks useful to me. I named it useWith
but I'm wondering if it's a function already known to functional programmers under a different name.
The function is related to compose
in that it returns a new function that combines several existing ones, but in a slightly different manner than compose
. The first parameter it receives is singled out; the remainder are treated uniformly. When the returned function is called, the arguments are passed respectively to each of these remaining functions, and the results, along with any unpaired arguments are sent to that first function, whose result is then returned. So if this is called with only two functions, and if the resulting function is passed a single argument, this is exactly equivalent to compose. But it has some additional features for multiple arguments.
The reason I wanted this function was that I was implementing something like the project
function
Michal Fogus presented in Functional Javascript, an equivalent of Codd's project
for an array of similar Javascript objects, and similar to SQL's select
verb. It is quite easy to write like this:
var project = curry(function(keys, table) {
return map(pick(keys), table);
});
// Used like this:
var kids = [{name: 'Bob', age: 3, eyes: 'blue', hair: 'brown'},
{name: 'Sue', age: 5, eyes: 'hazel', hair: 'blonde'}];
project(['name', 'eyes'], kids);
//=> [{name: 'Bob', eyes: 'blue'}, {name: 'Sue', eyes: 'hazel'}]
But I really wanted to implement it in a points-free style. But of course this wouldn't work:
var project = compose(map, pick); // NO!
...because there is no facility to pass through the second parameter, table
inside compose
.
That's where this new function comes in:
var project = useWith(map, pick);
I made it more generic than this case, though. The original approach was called using
with the parameters reversed, so that it read as a command: "Using pick, map". But that made it hard to extend to multiple parameters. I'd have to make the first one an array, or allow it to be either an array or a single function, and I didn't really want to go there. This seemed a much better solution.
I feel as though I can't be the first person with the need for a function like this. Is this a common pattern in FP languages? Is there a common name for this function? If not, are there suggestions for a better name than useWith
?
If you're curious, here's the implementation of useWith
, using a pretty obvious slice
, and a fairly standard curry
:
var useWith = curry(function(fn /*, tranformers */) {
var tranformers = slice(arguments, 1);
return function() {
var args = [], idx = -1;
while (++idx < tranformers.length) {
args.push(tranformers[idx](arguments[idx]))
}
return fn.apply(this, args.concat(slice(arguments, tranformers.length)));
};
});
I could have misunderstood something due to lack of javascript knowledge, but if map
is a curried function, and compose
returns a curried function, then compose(map, pick)
is project
, since map
is partially applied to pick
-- and partial application works only on the first argument. Here's the proof of what I mean:
compose map pick =
(\f g x. f (g x)) map pick = -- definition of compose
(\g x. map (g x)) pick = -- apply to map
\x. map (pick x) = -- apply to pick
\x. (\y. map (pick x) y) = -- eta-expansion of inner function
\key table. map (pick key) table -- combine and rename
(I assumed you know lambda calculus based on the name of your library.)
As you can see, this doesn't depend on the arity of map
-- you can eta-expand as often as you like, thus, no extra work is required for generalization. As long as everything is curried.
For having mixed-arity, curried and uncurried functions at the same time, there are combinators like these, but that's probably a bit too extreme.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With