[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
internal define (was: macros expanding into definitions)
Here's how I would describe the consensus that I perceive to be
<program> ::= <prog form>*
<body> ::= <body form>* <last form> -- lambda, let, letrec, etc. bodies
<prog form> ::= <exp> | (begin <prog form>*) | <def> | <syntax def>
<body form> ::= <exp> | (begin <body form>*) | <def>
<last form> ::= <exp> | (begin <body form>* <last form>)
<def> ::= (define <name> <exp>) | (define (<etc. etc.>) <body>)
Semantics of bodies can be given by transformation into expressions
involving hypothetical INITIALIZE! and LET-UNINITIALIZED special
forms, as follows: body is equivalent to
(LET-UNINITIALIZED ((var) ...) body')
where body' is the same as the body except that each (DEFINE var exp)
has been replaced by an (INITIALIZE! var exp).
The semantics(es) of INITIALIZE! and LET-UNINITIALIZED are identical
to those of SET! and LET, respectively, for valid programs. However,
it is an error for a SET! of a variable bound by LET-UNINITIALIZED to
dynamically precede an INITIALIZE! of that variable.
Now, it's possible that the proposal may topple under the weight of
these auxiliary concepts. But before you discard baby with bathwater,
note that (1) the description in the report needn't be quite so
formal, and (2) the uninitialized concept is already lurking in the
semantics of LETREC, whose boundary conditions are not described by
the source-to-source rewrite in the appendix. That is, the LETREC
rewrite holds for valid programs, but an invalid program can be
rewritten into a valid one. A LETREC rewrite that preserves boundary
conditions requires the equivalent of INITIALIZE! and
(letrec ((var exp) ...) body ...)
=> (let-uninitialized ((var) ...)
(let ((temp exp) ...)
(initialize! var temp)
(let () body ...)))
where temp ... is a set of fresh variables [not strictly needed].
OK, now that you believe all this, let's talk about unassignedness.
Uninitialized and unassigned are linguistically independent concepts.
Uninitialized comes from the constraints we'd like to impose on LETREC
and DEFINE, while unassigned comes from the different constraints we'd
like to impose on the independently proposed (define x) and (let ((x))
...) features. It's an error to reference a variable in either state,
but SET! is only an error if the variable is uninitialized.
I think some of the confusion here arose because people thought that
introducing (define x) and (let ((x)) ...) would allow us to reduce
liberalized internal definitions and perhaps even LETREC to them. No
such luck. If this is all too complicated for you, and you want to
throw something out, omit unassigned (by retracting or respecifying
the corresponding constructs), since the agreed-upon LETREC semantics
has already stuck us with the need for uninitialized.