1

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?

Will Ness
  • 69,019
  • 8
  • 93
  • 175
Iven Marquardt
  • 3,761
  • 1
  • 13
  • 30
  • 2
    nested bindings are defined with `let*`, mutually recursive bindings - with `letrec`. `let*` just translates into a series of nested one-binding `let`s, much like what you've shown. there's no recursion involved in this, no closures. – Will Ness Feb 01 '20 at 13:21
  • `bind` has no type, but you can give its invocations a type provided you assert the types of the default parameters. [Playground](http://www.typescriptlang.org/play/?ssl=1&ssc=14&pln=1&pc=17#code/MYewdgzgLgBARgSzAExgXhgHgIID4AUAZgFwz4CU6uM2la1hFA3AFAuIr74AexYArgFs4AUwBO6GACYANDACefIaIkZuMAFQxucgF5Lh4yfM0K61ANo6FegLrkgA) – Iven Marquardt Feb 01 '20 at 15:04
  • Why not just use `const` and `return`? Not everything needs to be an expression. – Aadit M Shah Feb 01 '20 at 15:16
  • @AaditMShah I love statements. What would life be without making and listening to statements? I just want to learn how local bindings are related to recursion. As I understand Will's comment `let*` depends on macros and is transformed to nested `let` during expansion. So the key to my q seems to be mutual recursion. – Iven Marquardt Feb 01 '20 at 15:32
  • 1
    but there is no mutual recursion in the example that you show. there is no shared scope, only nested scope. see also [this](https://stackoverflow.com/questions/15003518/confused-by-the-difference-between-let-and-let-in-scheme/15006018#15006018). – Will Ness Feb 01 '20 at 18:19
  • @WillNess I was referring to your 1st comment. You mentioned `letrec` depends on mutual recursion. At least this is how I interpreted it. – Iven Marquardt Feb 01 '20 at 18:22
  • 2
    not depends, expresses. you said "the key to [this] Q is mutual recursion", so I responded to that. just to clarify. – Will Ness Feb 01 '20 at 18:22

0 Answers0