The following combinator uses default parameters in a creative (some would say abusive) way and it behaves kind of like Scheme's letrec
*:
* Please correct me if I'm wrong, I don't know Scheme well
const bind = f => f();
const main = bind(
(x = 2, y = x * x, z = y * y, total = x + y + z, foo = "foo") => [x, y, z, total, foo]);
console.log(main);
It works but bind
has no type. Next I tried to manually encode the above main
function:
const app = x => f => f(x);
const main = app(2) (x =>
app(x * x) (y =>
app(y * y) (z =>
app(x + y + z) (total =>
app("foo") (foo => [x, y, z, total, foo])))));
console.log(main);
It may work but it is hideous. How can I avoid the nesting? I've played around with fix
and recursion but I have no clue how to express closures this way:
const fix = f => x => f(fix(f)) (x);
const letrec3 = f => fix(rec => acc => x =>
acc.length === 2
? acc.reduce((g, x) => g(x), f) (x)
: rec(acc.concat(x))) ([]);
const main = letrec3(x => y => z => total => foo => [x, y, z, total, foo]) (2) ("2 * 2") ("4 * 4") ("2 + 4 + 16") ("foo");
console.log(main);
Is there a recursive algorithm that effectively creates closures or local bindings, so that the current binding may depend on the previous ones?