[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
quasiquote
Date: Tue, 13 Apr 93 10:31:44 CDT
From: wright@cs.rice.edu (Andrew Wright)
Someone else who knows the history might comment, but the reason I see
for nesting levels is to permit substitution to work properly. Ie,
(define e '`(a ,b))
`(1 ,e)
is equivalent to:
`(1 `(a ,b))
This is a very good answer. The nesting rules simulate what you would
get if you did the expansion into CONS and friends naively,
inside-out, at read time, and your substitution rule is a consequence
of that. The description in terms of levels would be necessary even
if it were implemented at read time instead of macro-expand time.
Also, Scheme's backquote semantics matches Common Lisp's, which is
probably a good thing.
What I don't like is the sentence on page 12 of R4RS:
``Unpredictable behavior can result if any of the symbols quasiquote,
unquote, or unquote-splicing appear in positions within a <template>
otherwise than as described above.''
Consequently, Chez Scheme rejects:
`(quasiquote 1 2)
with an error, while MIT Scheme accepts it. This is probably an old
battle, but I would like to see R5RS clean this up.
I confess responsibility for this lossage. Back when R3RS was being
put together I really wanted the exact behavior of READ on backquote
forms to be specified, just as the result of READ is for quoted forms.
This is necessary in order to be able to write portable compilers that
call the built-in READ, instead of having to supply their own READ.
You can easily get screwed trying to write a compiler in Common Lisp,
for example, which doesn't specify backquote's read syntax (but then
cross-compilation is an iffy business in CL for innumerable other
reasons).
So the other authors were good enough to accept the particular
representation that I proposed. Alan Bawden objected at the time,
however, citing examples like the above. He said that the expansion
of backquote forms should happen at read time instead of macro
expansion time, so e.g. `(A ,B) might read in as (LIST (QUOTE A) B).
If you do expansion at read time, from the inside out, everything
works and you don't have to worry about occurrences of special markers
in your quasiquoted forms - whatever markers were inserted temporarily
by READ disappeared during the read-time expansion, and READ can
choose those markers to be objects that have no read syntax, thus
avoiding any confusion with what the user might have written. (I'm
not explaining this very well. Trust me, or ask Alan to explain.) I
said that it is very desirable to be able to redefine CONS, APPEND,
etc. without breaking backquote forms - after all, these are not
reserved words, as UNQUOTE and QUASIQUOTE were in R3RS - so expanding
into these things is unacceptable.
I learned the error of my ways, but not until after R3RS had gone to
press. Basically there is no choice but to use reserved words in the
representation (unless you want to start using non-symbols - syntactic
closures maybe? - but I guess that would be too radical for this
group). In R3RS / R4RS, these reserved words are UNQUOTE and
UNQUOTE-SPLICING (and QUASIQUOTE). But Alan's solution could work
just fine, if it had its own set of reserved words - if CONS and
APPEND can't be reserved, then how about using some more "obscure"
names, like perhaps QUASIQUOTE-CONS and QUASIQUOTE-APPEND? The set
might be a little larger (3 are sufficient), and redundant with
existing procedures, but it's not worse in spirit than the UNQUOTE
solution. So we would have
`(a ,quasiquote-cons)
read as
(QUASIQUOTE-CONS (QUOTE A) (QUASIQUOTE-CONS QUASIQUOTE-CONS (QUOTE ())))
or whatever, which is unambiguous.
I have now done my duty, and will allow others to discuss the merits
of this alternative, its details, and the tradeoff of "cleaning this
up" against being compatible with the past. Fixing the problem would
break many existing programs, and it's not obviously worth the bother,
but I don't feel strongly either way.
Jonathan
- References:
- quasiquote
- From: wright@cs.rice.edu (Andrew Wright)