[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Update to SRFI 72 (Sorry I'm lost)
On Wed, 31 Aug 2005, Keith Wright wrote:
Although the above quotation occurs three times almost verbatim,
in the abstract, the introduction, and the specification, it does
not get any clearer with repetition. As Brian Smith used the term
"reflective tower" it referred to an interpreter for a language
that could express modifications to its own interpreter. I don't
think that's what you are after, is it?
The second mention of the "infinite reflective tower" is followed
by a reference  to Richard Kelsey and Jonathan Rees
- The Scheme 48 implementation http://s48.org/
but a couple hours searching the Scheme 48 manual at that
web site turned up no mention of reflective towers, and not much
about macro expansion.
I'll try to rewrite this more clearly. I mean a reflective tower in the Scheme
48 sense, also called a syntactic tower by the authors, who indeed criticise
the word "reflective" as a misnomer, though it seems to be widespread in the
Scheme folklore. The Scheme 48 manual is notoriously cryptic, to the point of
unusability, but there is a mention on the page:
If someone else has a better reference to the Scheme 48 tower, I'd be grateful
Perhaps a better reference would be
Queinnec - Macroexpansion Reflective Tower</a>
I'll add the reference.
A couple of examples of odd scope rules just isn't enough for me
to figure out the plan. This seems to be a very big change from
the previous proposal, and not like anything that I understand well.
* Added BEGIN-FOR-SYNTAX.
Maybe this will help: In the example
(define x 1)
(begin-for-syntax (define x 2))
(let-syntax ((m (lambda (form)
(quasisyntax (list x ,x)))))
(m)) ==> (1 2)
one would get different answers depending on whether you evaluate the
sequence of expressions one by one in the REPL, or compile the whole thing and
then run it, *unless* the runtime x and the expand-time x live in separate
namespaces or, equivalently, runtime and expand-time variables have separate
It is still lexical scoping. Any programmer worth her salt will know that the
first x in (list x ,x) denotes a runtime variable and the second x an
expand-time variable, and be able to look up the appropriate lexically preceding
binding for each.
I consider this "invariance under compilation" property the right thing to do.
... the hygiene algorithm of this SRFI implements a refinement of
lexical scoping that takes into account the level of use of an
identifier in determining its meaning.
might be better worded as: the algorithm of this SRFI totally ignores
lexical scoping by making the meaning of an identifier depend upon
an invisible property called its "level" rather than its position
in the source code. ...but I have already stated my objections
when you first brought up this idea.
I think it is clear that one has different environment bindings at expansion
time and at runtime. In fact, there is no reason that the expansion-time
bindings have to implement standard Scheme. For example, the compile-time CAR
can be different from the runtim CAR. So the compile-time language can be
different from the runtim language.
For argument's sake, let's call the runtime-language Scheme and the
compile-time language Pascal. Now Pascal binding forms and Scheme
binding forms a priori have nothing to do with each other, so I would be very
surprised if the inner Pascal LET were to affect the x in (syntax x) at all in
(let ((x 1))
(let-syntax ((m (lambda (form)
(let ((x 2))
(m))) ==> 1
Indeed, the x in (syntax x) represents a Scheme variable, not a Pascal variable.
It should therefore be bound by the enclosing outer Scheme LET. In other
words, Scheme code and Pascal code should have separate lexical scopes.
* Added SYNTACTIC-WIND.
This allows one to do a computation before and after expanding a block of code.
It is useful for maintaining environments at expansion time when implementing
things like syntax-case and pattern matchers. For example, in the syntax-case
macros I used it for maintaining the environment of pattern variables.
I included it because without it I do not know how to write syntax-case as a
library macro. I do not wish to specify syntax-case as a primitive.
* Removed EXPAND.
Because just like EVAL, EXPAND really does not make sense without a second
argument specifying the environment. I did not wish to overcomplicate the SRFI
with a complicated explanation (and implementation) of a primitive that is used
mainly for debugging.
...and if it is gone, why is this code in the section
on the reflective tower?
(for-each (lambda (form) (eval (expand form))) sequence)
== (for-each eval (map-in-order expand sequence))
The "schematically" was meant to indicate that it is just a pseudocode
expression of the previous verbal phrase.
In other words, would the old srfi be compatible
with the reflective tower, except that it would give errors
(identifer used outside its scope of definition) in some cases
where the tower would find and use a binding occurrence that
would appear to be shadowed?
My view is that it is just wrong for a binding form in one phase to affect
variables in another phase at all. I consider the out-of-scope errors in
comparable macro systems a bug.