Scheme complains that in the code below, the x in (+ x 1) is undefined:
(letrec ((x 1)
(y (+ x 1)))
y)
- Chez Scheme:
Exception: attempt to reference undefined variable x - MIT Scheme:
;Unassigned variable: x
So, I defined another x:
(let ((x 999))
(letrec ((x 1)
(y (+ x 1)))
y))
However, the Scheme implementations still complain that the x in (+ x 1) is undefined. What is going on? Clearly, I have already defined x.
That's not how
letrecworks. You can think ofletrecas if it did something close to this (see R7RS, 4.2.2 for instance).is equivalent to
Where
<illegal-value>is some thing you are never meant to refer to, and which implementations may make illegal to reference.This is not quite what
letrecdoes, because in the above expansion the assignments happen in a defined order, whereas inletrecthe evaluations of the initialisation forms do not. So a fancier expansion might be usingletfirst, since its order of evaluations is also non-defined:Now we can see that
will fail, because the expansion inserts another
letwhich shadows the outer binding:and you can see that what is going wrong is when
t2is bound toawhich refers to the current value of the binding ofawhich is<illegal>, while the outerawhose value is999is inaccessible.On the other hand, this:
both will work, and will return true, because in the expansion
(b)will be called after theset!s.The most common use of
letrecis that it allows recursive functions to be bound: in something likeThen
fneeds to refer to the same binding offin order to work, but it does not actually look at the value of that binding until the function is called, by which time all is well.See my other answer for some other possible uses of
letrechowever.