[plt-scheme] How is letrec different from letrec* in its use?

From: Grant Rettke (grettke at acm.org)
Date: Sat Feb 14 00:01:14 EST 2009

On Fri, Feb 13, 2009 at 6:35 AM, James Coglan <jcoglan at googlemail.com> wrote:
>> I just read the spec for both letrec and letrec* and I see that the
>> former is not evaluted in any other but the latter is evaluted from
>> left to right. I am not getting the difference in their use. May
>> someone please provide an illuminating example?

> (letrec) is like (let), but the evaluations take place *inside* the lambda,
> changing their scope. The evaluations are not supposed to depend on each
> other so evaluation order is not important (like for (let)).
> (letrec ([x 1]
>          [y 2])
>   (+ x y))
> is equivalent to:
> ((lambda ()
>   (define x 1)
>   (define y 2)
>   (+ x y)))

This is how I interpreted its behavior from the spec:

(define-syntax my-letrec
  (syntax-rules ()
    ((_ ((var init) ...) body)
     (let ((var #f) ...)
       (set! var init) ...

 ((a (lambda (n) (when (< n 5) (b (add1 n)))))
  (b (lambda (n) (when (< n 5) (a (add1 n))))))
 (a 0))

#;(let ((a #f)
        (b #f))
    (set! a (lambda (n) (when (< n 5) (b (add1 n)))))
    (set! b (lambda (n) (when (< n 5) (a (add1 n)))))
    (a 0))

Are we saying the same thing? Is this right?

> Finally, (letrec*) is like (let*) but it uses (letrec).
> (letrec* ([x 1]
>           [y 2])
>   (+ x y))
> is equivalent to:
> (letrec ([x 1])
>   (letrec ([y 2])
>     (+ x y)))

I see. This allow for mutually recursive definitions; but as Sam said
you can predict about behavior in situations when you are not *only*
binding lambda expressions.

I am wondering why would people use letrec for anything other than
binding lambda expressions if it is impossible to reason about its
behavior? Or rather, why would it allow anything other than lambda
expressions to be bound if you can't predict the behavior?

Posted on the users mailing list.