Many of the issues raised recently seem to me to point to a common basic
question: how intimately runtime and expand-time should be coupled. At
the other extreme, we would have a separate language for manipulating
syntax, not accessible to the runtime environment in any way; at the
other extreme, macros and syntax objects are first-class runtime objects
and the runtime environment provides reflective facilities for working
with those.
Different aspects where we need to take a stance in this include:
- the separateness of syntax and runtime namespaces;
- the opaqueness of syntax objects;
- the interface of the expander;
- specifying the situation(s) where the expander is invoked.
My personal view is that Lisp was always meant to be its own
metalanguage, and that property should be preserved as long as it is
possible and practical. Thus, we should seek a way to bring the syntax
language and the runtime language as close to each other as possible.
SRFI 72 seems to bring abstraction to traditional Lisp macros by
separating the concepts of identifier and symbol. This has widespread
ramifications, because a program's external representation no longer is
a representation of its syntax tree, but an impoverished version where
identifiers are replaced by symbols. I think we should redefine the
relationship between (eval), (load) and the toplevel of a Scheme
program.
For example, what (eval) handles should probably be syntax objects, not
data. But this would break the current interface. Maybe we could
define (in the SRFI) the primitive operations datum->syntax (together
with syntax->datum), syntax-expand, and syntax-eval. Then, expressions
on toplevel of the program would be defined to run through read,
datum->syntax, syntax-expand and syntax-eval; and eval would effectively
be the composition of datum->syntax and syntax-eval. This way, users
could call syntax-expand by themselves, syntax-expand wouldn't make an
implicit syntax->datum.
I think new macros definitions should be registered in the evaluator, so
that the expander will not have any side effects of its own. This would
require us to define that toplevel expressions are expanded and eval'd
one at a time, otherwise one could not count on a macro being available
after its definition.
I also wish that the syntax and runtime namespaces could be unified.
But there should probably be a way to find out whether a given binding
is a macro binding or not. Could we have a macro? predicate?
And yes, of course I support transparent syntax objects.
I know this increases the burden of the SRFI, specifying not only the
definition mechanisms of macros but also how they are invoked. There is
the risk that the design of the interaction between the runtime
environment and the expander is bad and everyone will suffer. But if we
manage to make it right, macros will become a concrete part of the
language, programmers will gain introspective abilities to the macro
system, and everyone will be happy. :)
Panu
--
personal contact: xxxxxx@iki.fi, +35841 5323835, +3589 85619369
work contact: xxxxxx@helsinki.fi, +35850 3678003
kotisivu (henkkoht): http://www.iki.fi/atehwa/
homepage (technical): http://sange.fi/~atehwa/