Here are some streamlined versions of @RobG's excellent answer:
function add(n) { function calc(x) { return n+=x, calc; } calc.valueOf = function() { return n; }; return calc; }
The slight difference is that here calc simply updates n and then returns itself, rather than returning itself through another call to add , which pushes another frame onto the stack.
Explicit expression of self-replication
calc is thus a pure self-reproducing function, returning itself. We can encapsulate the concept of "self-replication" function
function self_replicate(fn) { return function x() { fn.apply(this, arguments); return x; }; }
Then add can be written, perhaps in a more self-documenting way, since
function add(n) { function update(x) { n += x; } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; }
Parallel to the # reduce array
Please note that between this approach there is some parallelism of multiple function calls and Array#reduce . Both reduce the list of things to one value. In the case of Array#reduce list is an array; in our case, the list is the parameters for repeated calls. Array#reduce defines a standard signature for reducer functions, namely
function(prev, cur)
where prev is the "accumulator" (so far), cur is the new value that is being supplied, and the return value becomes the new accumulator value. It seems useful to rewrite our implementation to use a function with such a signature:
function add(n) { function reducer(prev, cur) { return prev + cur; } function update(x) { n = reducer(n, x); } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; }
Now we can create a more general way to create reducers based on replication based on the reducer function:
function make_repeatedly_callable_function(reducer) { return function(n) { function update(x) { n = reducer(n, x); } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; }; }
Now we can create add as
var add = make_repeatedly_callable_function(function(prev, cur) { return prev + cur; }); add(1)(2);
In fact, Array#reduce calls the reducer function with the third and fourth arguments, namely the index into the array and the array itself. The latter does not matter here, but perhaps we would like something like the third argument to find out what an "iteration" is, which we can easily handle, just by tracking the use of the variable i :
function reduce_by_calling_repeatedly(reducer) { var i = 0; return function(n) { function update(x) { n = reducer( n, x, i++); } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; }; }
Alternative approach: value tracking
There are certain advantages to tracking intermediate parameters called by a function (using an array) and then performing the reduction at the end, rather than as you move. For example, we could make Array#reduceRight type of things:
function reduce_right_by_calling_repeatedly(reducer, initialValue) { var array_proto = Array.prototype, push = array_proto.push, reduceRight = array_proto.reduceRight; return function(n) { var stack=[], calc = self_replicate(push.bind(stack)); calc.valueOf = reduceRight.bind(stack, reducer, initialValue); return calc(n); }; }
Non-Primitive Objects
Try using this approach to create objects ("expand"):
function extend_reducer(prev, cur) { for (i in cur) { prev[i] = cur[i]; } return prev; } var extend = reduce_by_calling_repeatedly(extend_reducer); extend({a: 1})({b: 2})
Unfortunately, this will not work because Object#toValue is only called when a primitive object is required by JS. Therefore, in this case, we must explicitly call toValue :
extend({a: 1})({b: 2}).toValue()