compile/letrec
Symbol: compile/letrec
Syntax: (letrec BINDINGS BODY ...)
Bindings: A list of binding forms; each is [SYM EXPR] or (EXPR as: SYM),
the same shape compile/let accepts. There is no named form.
Use-case: Bindings whose values may refer to each other. Every name is declared in one child scope before any value is evaluated, so a lambda in one binding can call a function bound by another.
Behaviour: Pushes a child namespace and declares each name with no value.
Each right-hand side is then compiled and stored with VAR_STORE, left to
right, and the body runs in that scope. A name read before its own value is
stored raises, so the mutual references have to be inside function bodies
rather than evaluated during the binding pass.
A name/value count mismatch raises SpecialError at compile time.
Examples:
>>> (letrec [[even? (lambda [n] (if (== n 0) True (odd? (- n 1))))]
... [odd? (lambda [n] (if (== n 0) False (even? (- n 1))))]]
... (even? 10))
True
Self-reference works the same way:
>>> (letrec [[f (lambda [n] (if (== n 0) 1 (* n (f (- n 1)))))]]
... (f 5))
120
See also: compile/let, compile/define.