Dear Taylan, thanks for pointing me to the use of letrec* in this case. The case though was meant as an example to illustrate the problem. I'm currently implementing an R5RS interpreter and was unsure if I can handle letrec as illustrated below in the second case or if I need to implement it as guile does.
Cheers, Alex On Mon, Nov 28 2022, 15:07:39, Taylan Kammer <taylan.kam...@gmail.com> wrote: > On 28.11.2022 09:33, Alexander Asteroth wrote: >> >>> scheme@(guile-user)> (letrec ((b a)(a 7)) b) >>> $1 = 7 >> >> should be equivalent (of course in a new scope) to: >> >>> scheme@(guile-user)> (define b #nil) >>> scheme@(guile-user)> (define a #nil) >>> scheme@(guile-user)> (set! b a) >>> scheme@(guile-user)> (set! a 7) >>> scheme@(guile-user)> b >>> $2 = #nil >> > > Hi Alex, > > The only reason the first example returns 7 is because Guile *happens* to > bind a to 7 before it binds b to the value of a. The code could have as > well returned another value (IIRC Guile uses #<unspecified>) had Guile > decided to evaluate the arms of the letrec in a different order. > > As per the part of the standard you quoted: > >> the 〈init〉s are evaluated [...] (in some unspecified order) > > That's what the "unspecified order" in the parentheses is referring to. > > On the other hand, in your second code example, there's a strict order > in which the various expressions will be evaluated. In the moment you > type in (set! b a), the value of a has not yet been changed to 7. > > If you want to use letrec but with a specific order of evaluation of the > arms, then you can use the letrec* variant: > >> (letrec* ((a 7) (b a)) b) >> $1 = 7 > > This will definitely work, without relying on chance or an implementation > detail of Guile.