Suppose we wanted to build big structures by using lambdas as "holes" representing the location where we want to add new data. For example, here we build [0,[1,[2,null]]] using that idea:
builder_0 = hole => hole; // hole => hole;
builder_1 = hole => builder_0([0,hole]); // hole => [0, hole];
builder_2 = hole => builder_1([1,hole]); // hole => [0, [1, hole]];
builder_3 = hole => builder_2([2,hole]); // hole => [0, [1, [2, hole]]];
// prints [0,[1,[2,null]]], but will stack overflows if too many lines
console.log(JSON.stringify(builder_3(null)));
This works fine. We can also do it in a loop:
let builder = hole => hole;
for (let i = 0; i < 1000; ++i) {
let last_builder = builder;
builder = hole => last_builder([i, hole]);
};
console.log(builder(null));
This works too, but this algorithm will stack overflow if the limit is larger than 10000. The problem is that, since last_builder([i,hole]) isn't evaluated inside the hole => ... closure, it will build up chunks of unevaluated lambdas that will rapidly consume the whole stack. Note that [0,[1,[2,null]]] is just a useless example, JavaScript will fail to build any large structure using the hole-based technique above (think of trees, JSONs, immutable containers and so on).
Tail-call optimization and trampolining won't help here, as we don't even have a recursive function to begin with. Is there any clever trick that allows this kind of functional idiom to work without stack overflows?