I’ve made some progress on the “exercise” piece.
With this update to with_list you can call the function from the injector with as many arguments as you like, as long as xs remains at the end.
var with_list = function (f) {
var arity = f.length;
return function () {
var funcArgs = Array.prototype.slice.call(arguments, 0);
if (arity > 0 && funcArgs.length !== arity - 1) {
throw "Oops!";
}
return function(xs) {
args = Array.prototype.slice.call(arguments, 0);
args.unshift(args.pop()); // move xs before other args
return f.apply(this, funcArgs.concat(args));
};
};
};
You can now inject in to functions for grep, map and each
For example, here is grep, called as grep(pred, xs)
var grep = injector([], function (rs, x) {
var pred = args[1];
var rx = new RegExp(pred);
if (rx.exec(x)) {
rs.push(x);
}
return rs;
});
var result = grep('\\\\d{2}', [7, 23, 'String with 1 number']);
alert(result); // 23
The double blackslashes on \\d is only due to it being written as a JavaScript string, so that the script doesn’t misinterpret \d as an escaped character.
Here’s the rest of the code that connects everything together, which fits in between the above two code blocks.
var inject = function (i, f, xs) {
var args = arguments,
r = i,
index;
for (index = 0; index < xs.length; index += 1) {
r = f(r, xs[index]);
}
return r;
};
var injector = with_list(inject);
There is only one coding concession currently being made, and that is that the arguments from (pred, xs) are made globally available as (xs, pred) in an args variable, so that the injected function can gain access to them.
When inject() is called is expects the first argument to be the list, so we po off xs from the end of the arguments, and moving it to the front instead so that (xs, pred) is passed to inject.
We can now gain access to those same arguments, but it comes at the cost of polluting the global namespace with an args variable.
It’s not as clean as I would want, but provides something that can be made to work with grep, map and each.
It may also be possible for someone to clean things up a bit further too.