For every 100% compliant R7RS-small program that does not rely on any implementation-specific or undefined behavior, is it true that every instance of letrec
in the program can be replaced with letrec*
without causing any change in behavior? In other words, is there any R7RS-small program where an appearance of letrec
cannot be substituted with letrec*
?

- 9,805
- 5
- 46
- 92
1 Answers
I think that the answer is yes, it can, assuming that the form is not 'an error' in R7RS terminology (but see note at end). In particular I think that if there's a form like
(letrec ((v1 <e1>) (v2 <e2>)) ...)
Then it must be possible to evaluate <e2>
without referring to the value of v1
, but that binding does actually exist when <e2>
is evaluated: it is just an error to refer to it. So in particular this is not allowed:
(let ((a 1)) (letrec ((a 2) (b a)) ...))
because the binding that the init for b
refers to is that established by the letrec
, not that established by the let
, but it is not yet legal to refer to the value of that binding.
That being the case then if you simply replace letrec
by letrec*
then <e2>
still will not refer to the value of v1
and thus the results will be the same.
The converse is not true:
(letrec* ((a 1) (b a)) ...)
is fine, but you can't replace the letrec*
by letrec
there.
That being the case I'm unclear what useful purpose letrec
serves (perhaps this is why Racket's letrec
has the semantics of Scheme's letrec*
).
Note an earlier version of this answer came to the opposite conclusion. I am now not convinced I understand things well enough.

- 7,040
- 2
- 12
-
I tried the `letrec` example in MIT Scheme 11.2, Chibi 0.10.0, and Guile 3.0.7. MIT Scheme gives an error: `Unassigned variable: a`, Chibi returns `2`, and `guile --r7rs` returns `2`. Why do they not return `1` as you claim? – Flux Dec 01 '21 at 15:15
-
Yes, I am not sure my answer is right – ignis volens Dec 01 '21 at 15:22
-
@Flux: I think I was wrong: the new version of the answer comes to the opposite conclusion: yes, you can do this. However I think we need a proper Scheme expert not an old lisp hacker who thinks they understand Scheme but perhaps does not like me. – ignis volens Dec 01 '21 at 16:06
-
"if you simply replace `letrec` by `letrec*` then `
` still will not refer to the value of `v1` and thus the results will be the same." — Are you sure about this? `(letrec* ((a 2) (b a)) a)` returns `2`. – Flux Mar 22 '22 at 02:15 -
@Flux: Yes, that's right. `(letrec ((a 2) (b a)) ...)` is an error since the form `a` refers to the value of the binding of `a`: what I claim is that all `letrec` forms *which are not errors* can be replaced by `letrec*` forms. If *all* `letrec` forms are blindly replaced by `letrec*` forms then some errors will become legal code, like this case. – ignis volens Mar 22 '22 at 09:51