[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
meaning of local define
Am I confused! I don't understand why good style allows global DEFINE
to be used to define things other than procedures, but not local DEFINE.
It seems to me that in general one ought to be able to use the same
construct in the same way no matter where it appears. Call this
principle "stylistic transparency". Am I confused?
I agree with this... I guess this is why I thought it might be better to
allow define's to be interspersed with other expressions in
lambda-bodies, and saying they're evaluated sequentially, for uniformity
with "top level".
The problem is this:
In the following (horrible) code
(define (quux x) (* x x))
(define (foo y)
(define bar (quux y))
(define (quux x) (* x x x))
(quux y))
We have various options:
1) The first reference to QUUX gives the value of the outer QUUX and
the second gives the value of the inner QUUX since the inner one has
not been defined yet. This is what the interpreter in chapter 4 of
S&ICP does. This seems very ugly since it implies one of 2 things:
- Definitions modify environments to have new bindings. The definition
causes a side effect to the environment where it occurs. This is
pretty ugly.
- Definitions create new environments where the rest of the
expressions are evaluated. This has clear problems with mutual
recursion.
2) Both references result in the inner QUUX since the DEFINEs are
equivalent to a LETREC, and there exists an order in which the
definitions can be evaluated which gives this result. This would be
easy to arrange if Scheme were evaluated in normal order, but hard
(in general) given that it is applicative order.
3) It is an error because the definitions occur all in parallel but
the values are assigned sequentially, and thus QUUX is bound but not
assigned on first use. This is what MIT Scheme does currently (and
used to do for top level).
I would like 2 to hold, but it unfortunately does not. Making 3 the
official semantics would be like specifying an order of argument
evaluation which people would then take advantage of. Restricting the
values to be lambda expressions guarantees that the result does not
depend on the order of evaluation, while attempting to extend this
(constants, expressions which depend only on outer variables, etc.)
gets us into a sort of operational semantics.
The sort of thing CPH and I are trying to avoid is the same thing that
I (we ?) abhor about the definition of REC and LETREC, namely that
(rec a (cons 3 a))
does not work, while
(rec a (cons 3 (lambda () a)))
does.
We are making the implementation visible in the language definition.
BTW, I restrict my use of top level DEFINE so that it does not depend
in the potential sequentiality of evaluation.