[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

meaning of local define

LETREC may evaluate the right-hand sides in any order it pleases.  But
one could expect for several reasons that local DEFINEs are evaluated
left to right (or top to bottom, depending on where the line breaks
are).  The conjunction of these properties is in contradiction with the
assertion that local DEFINE's can always turn into a LETREC.

This can make a difference when a user tries to figure out whether
expressions like the following will return a well-defined result:

  (define (foo x)
    (define bar (1+ x))
    (define baz (* bar bar))
    (/ baz 6))

According to the documentation of DEFINE, this is equivalent to

  (define (foo x)
    (letrec ((bar (1+ x))
	     (baz (* bar bar)))
      (/ baz 6)))

I'm not a big fan of local define's, but I think that if they are
implemented, they should have right-to-left semantics.  I believe
local-DEFINE partisans will agree with this.

One solution is to introduce a new special form LETREC* which evaluates
the right-hand sides from top to bottom, and explain local DEFINE's in
terms of that.  So the example would be equivalent to:

  (define (foo x)
    (letrec* ((bar (1+ x))
	      (baz (* bar bar)))
      (/ baz 6)))

But LETREC* would otherwise be of very marginal usefulness, and we don't
need more secial forms.

So what I propose to do is to document the (LET ((var) ...) ...)  and
(DO ((var) ...)...) syntax, with the meaning CPH described, and explain
local DEFINE's in terms of LET and SET!, mentioning that in the case
that the right-hand sides of all the DEFINE's are all LAMBDA's, the
LETREC expansion would work just as well.  Sorry to reverse my former
opposition to this feature, but I hadn't thought of this before.
Opinions?  Any ideas about other ways to describe DEFINE?

The funny thing about (LET ((var)) ...) is that it's the only documented
way to get a variable bound to an uninitialized location which it is an
error to access.  This means that the correspondence between (LET ...)
and ((LAMBDA ...) ...) isn't as direct as it ought to be, since there's
no way that it can be an error to refer to a variable bound by a
LAMBDA-expression.  LET is primitive in Common Lisp (for other reasons),
and I never liked that.  On the other hand, this would give us an
opportunity to describe LETREC in terms of LET and SET! (exercise for
the student: how to make sure that the rhs's are evaluated in an
indeterminate order?).  I sniff another special form and semantic
complexity here.  What to do?