[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Macros again: read first
I have tried to reformulate my original message to answer some of JAR's
questions (there have been several exchanges between the two of us). This is
not a complete counterproposal and I don't have the time to come up with a
complete counterproposal. The purpose of this note (and its predecessor) is
to stimulate the committee to think in different ways about the issue of
macros and related matters.
1. Old-style macros have two purposes. First, they are used to extend
the set of available syntactic facilities. Second, they also have the
power of performing arbitrary computations on their input expressions
and the existing environment at compile time.
2. From my point of view, the extension of syntax is the addition of
syntactic forms to (a possibly extended) RRRS and the definition
of their semantics via an equivalence with already available facilities.
It follows that an extension of syntax is a map from (abstract syntax) trees
to (abstract syntax) trees. These tree domains are only a subset of the
domain of S-expressions and that is the important point.
Because the input/output domains are tree domains, i.e., they neither
posses state nor are they circular (this does not mean that they cannot
contain closures that are circular or have state), there is no need to use
side-effects for the manipulation of the input/output structures.
Assignments exist for the sole purpose of creating circularities and of
modeling state [NOTE: People use assignments for other purposes as well, but
these (first-order) uses can be eliminated without restructuring the entire
program (as in store-passing and continuation-passing style programming for
the general solution].
In the same vein I can argue against call/cc the second, non-functional
computational primitive (the uses for expansion time can be anticipated by
the expander as opposed to the transform function). In short, the
manipulation of abstract syntax trees requires nothing but the purely
functional subset of Scheme and this should be accounted for.
3. According to the preceding explanation, I call "macros" the set of
unrestricted transformation functions, which possibly use side-effects,
jumps (i.e. call/cc) etc.; "extend-syntax" is the facility which implements
functional transform functions.
4. Would Eugene's extend-syntax do it?
No, it is too powerful. It provides a WITH-construct for arbitrary
manipulations. [I believe the facility was added for macro-lovers
but Eugene can answer this better.] The WITH must be restricted so
that it conforms with the functional spirit. For inserting circular closures
or closures with state in the output tree I perceive the need for a more
expressive target language for the expander, i.e. a language where such
things can be written down. [I personally see a need for this and have used
this quite often, but as I said it suffices to extend the target language
or to accept a restricted with.]
The pattern language of Eugene's extend-syntax is not essential. A
restriction of MacroScheme to cons, car, cdr, map etc and and exclusion of
set!, set-car!, set-cdr!, eq?, etc. should do it although I believe that
the pattern language is in most instances more convenient. [Hundreds of
students at Indiana get along with it and encounter very few problems so
I also think that it is not difficult to learn.]
Side-effects for debugging. I have had to debug hundreds of extend-syntax
macros in the past 2 or 3 years (and several of the transformers). I have
practically never used side-effects in the WITH-clauses but always in the
expansion part of the macros. Perhaps the pattern languages has helped,
perhaps I am too optimistic. On the other hand, I could also imagine that
we add debugging aids to the functional MacroScheme language. I can see
that this point deserves discussion.
[JAR was disturbed by the rhetoric of this note. If there is any, I ask you
to overlook it.]