[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 [11] 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:

  http://s48.org/1.2/manual/s48manual_33.html

If someone else has a better reference to the Scheme 48 tower, I'd be grateful for it.


Perhaps a better reference would be
<a href="http://www2.parc.com/csl/groups/sda/projects/reflection96/abstracts/queinnec.html";>
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 lexical scopes.

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 phrase:
... 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 the following.

  (let ((x 1))
    (let-syntax ((m (lambda (form)
                      (let ((x 2))
                        (syntax x)))))
      (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.

Oy.


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.

Why?


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.

Cheers
Andre