With equational syntax,
letrec x = init-x
y = init-y
body....
the restriction is that no RHS init...
expression can cause evaluation of (or assignment to) any of the LHS variables, because all init...
s are evaluated while all the variables are still unassigned. IOW no init...
should reference any of the variables directly and immediately. It is OK of course for any of the init...
s to contain lambda-expressions which can indeed reference any of the variables (that's the purpose of letrec
after all). When these lambda-expressions will be evaluated, the variables will be already assigned the values of the evaluated init...
expressions.
The authors say, to require all the RHSes to be lambda
-expressions would simplify the implementation, because there's no chance for misbehaving code causing premature evaluation of LHS variables inside some RHS. But unfortunately, this changes letrec
's semantics and thus is not an option. It would also prohibit simple use of outer variables in RHSes and thus this new cut-down letrec
would also be less general and less convenient.
You also mention named let
but it is not equivalent to letrec
: its variables are bound as-if by let
, only the looping function itself is bound via letrec
:
(let ((x 1)(y 2))
(let g ((x x) (y x))
(if (> x 0) (g (- x y) y) (display x)))
(display x))
01
;Unspecified return value
(let ((x 1)(y 2))
(letrec ((g (lambda (x y)
(if (> x 0) (g (- x y) y) (display x)))))
(g x x)) ; no 'x' in letrec's frame, so refer to outer frame
(display x))
01
;Unspecified return value