[plt-scheme] about letrec and continuation : which behavior is correct ? and why ?

From: Abdulaziz Ghuloum (aghuloum at cs.indiana.edu)
Date: Wed Aug 20 15:44:21 EDT 2008

On Aug 20, 2008, at 11:27 AM, Joe Marshall wrote:

> Option 4:  An implementation *may* implement letrec as a binding
> followed by an assignment, or it *may* implement letrec as a
> fixed point, or it *may* mix the two.

This is precisely what I do in my compiler.

> Returning to an <init> continuation
> may cause re-assignment or rebinding at the discretion of the
> implementation.

How is this better than raising an exception?  (Note, Ikarus does
not raise such exceptions, so, it is far less work for me and far
more efficient for Ikarus to not introduce these checks for programs
that return more than once to an <init>, but I still don't see that
choosing to rebind or to assign depending on the implementation's
choice is better than raising an exception)

> Alternatively, the right hand side of the letrec could be restricted.

No!  Any restriction like that invalidates way too many valid and
perfectly good programs that I do write all the time.

> I rarely use letrec (or internal define) for arbitrary values.  I  
> almost
> always use letrec (or internal define) for procedures only.

I can't say the same.  For example, I consider parameters (i.e.,
the result of calling make-parameter), record accessors, mutators,
constructors, etc., to be procedures even if they're obtained by
procedural means (from non-lambda expressions).

This is a simple sequence of definitions:

   (define make-adder (lambda (n) (lambda (m) (+ n m))))
   (define add1 (make-adder 1))

Do you never write code like this?

> If this
> were the case, then you'd have to explicitly have a side effect in
> the code above:
> (let ((x (list #f)))
>   (set-car! x (lambda () x))
>   (eq? x ((car x))))
> Which, frankly, is a better way of writing this than the letrec
> because it is obvious that some side-effecting is going on in
> order to create magic circular structure such that
> (eq? x ((car x))) could evaluate to #t.

I agree that this is clearer and that letrec/call-cc tricks are
good for puzzles only and are never useful in practice.  However,
ruling out all non-lambdas or non-trivial expressions from letrec
and internal defines is an overkill; especially when the motivation
for doing so is just to disallow such puzzles.


Posted on the users mailing list.