[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

a modest backquote proposal



I would like to propose the following: we should agree on a standard
internal form for backquote forms.  That is, if a portable Scheme
program does (READ) and the available input is e.g. "`(FOO ,BAR (A ,@BAZ
B))", or if the expression '`(FOO ...) occurs in the program itself, the
program should be able to detect the fact that it has its hands on a
backquoted form, and take it apart and do something meaningful with it.
I would like the situation to be exactly the same as that of the 'FOO
syntax, where we know e.g. that (CAR ''FOO) => QUOTE and (CADR
''FOO) => FOO.

Just to make this concrete, here is one form that this proposal could
take: we could say that '`(FOO ,BAR (A ,@BAZ B)) is semantically
identical to '(#!QUASIQUOTE (#!UNQUOTE BAR) (A (#!SPLICE BAZ) B)).  We
need not specify what the objects #!QUASIQUOTE etc. are; they could be
symbols or special constants.  All that's needed is e.g. that (EQ?
'#!UNQUOTE '#!UNQUOTE) will work, that is, you get an EQ object each
time you read that syntax - the same situation as with symbols.

Thus we would have:  (CAADR '`(FOO ,BAR)) => #!UNQUOTE, and so on.

Note that this implies nothing about implementation except that the
"expansion" of backquote forms into calls to LIST etc., if indeed that's
how it's done, isn't generally done at "read time," but rather at
"compile time" or "macro expansion time".  (Expansion at read time would
of course be correct if the file was being read by LOAD and the
backquote form was known to occur outside of a QUOTE special form, etc.
All that's important is behavior detectable by user code.)  We would
just need to add #!QUASIQUOTE as a new special form or macro.  I know
that this would be a trivial change to MIT Scheme and T, for example,
since they already work this way.

Now here's the rationale:

(1) This removes a wart in the meaning of READ and QUOTE.  Without this,
there is absolutely nothing in the report which guarantees that reading
or quoting backquote forms is even legal, much less that it has a
predictable meaning.  But the absence of a representation for backquote
forms is the only obstacle to this.  Given such a representation, we
have a very nice general syntactic property: any sequence of terminals
which may be derived from the the <expression> nonterminal may also be
derived from the <datum> terminal.  That is, READ and QUOTE give
standard representations of programs as data.

(2) As a consequence, it will be possible to write portable
interpreters, compilers, cross-compilers, macroexpanders,
cross-reference programs, pretty-printers, readers, and so forth, which
will work on any program written in RRRSS, even those that use
backquote.

It seems to me that the desirability of being able to write
meta-programs would far outweigh any arguments about implementation
preemption.  I guess I might be asking some of you to modify your
implementations (e.g. some implementations might be expanding at read
time), so there's a tiny bit of work involved in this, but I think it
would generally be a very easy change for most implementors to make.
(By the way, there is a subtlety involved in expanding nested backquote
forms AFTER read time which I'll explain under separate cover if someone
asks me to.)

The fact that Common Lisp doesn't have this feature has made it
difficult to write a portable implementation of RRRSS in Common Lisp.
To do it right I'll have to define my own backquote read macro and
expander, which is silly of course.  The situation is worse in Scheme,
which doesn't have read macros - one would actually have to write a
reader in order to write any portable meta-program.

[Unrelated footnote: LOAD and EVAL are equipotent; either can be
implemented in terms of the other.  RRRS has one but not the other.]