[comp.lang.scheme] macros, understanding of macros

matthias@leto.rice.edu (Matthias Felleisen) (03/10/91)

CLAIM: Disciplined uses of macros can be reduced to the uses of
procedures. They are therefore as understandable (or even more so) as
uses of procedures as far as their semantics is concerned.

  [** Distilled by many hours of discussions with Bruce Duba, Dan 
  Friedman, Tim Griffin, Todd Jonkers, and Eugene Kohlbecker, and
  by even more hours of teaching the use of macros at Indiana and 
  Rice **]

DEFINITION: Disciplined macros. 
  (1) A disciplined macro is equivalent to a new syntactic 
      (special) form, i.e., its definition changes the syntax of 
      the language. It exists before the beginning of time of 
      all code. It translates syntax into syntax of the base 
      language (the one we thought was unextended). 
  (2) A disciplined macro is used in the following circumstances: 
      * introducing a new binding structure,
	e.g., let, letrec, coroutine when expanded into lambdas; 
      * imposing an evaluation order on expressions that 
	is not guaranteed by  procedure application,
	e.g., cond, case, record-case when expanded into if;
      * implicit quoting by transforming a syntactic token that is 
	apparently used as an identifier into a symbol, 
	e.g., case tag lists when expanded into quote lists. 
      * cosmectis for procedure application or one of the above 
	three cases: add embellishing keywords,
	e.g., like THEN and ELSE to if. 

JUSTIFICATION OF CLAIM: It is easy to show that each use of a macro
can be translated into the use of a procedure, with appropriate
changes to instances of macros. 

   1. Consider the first use: the introduction of new bindings. Replace
   by using lambda explicitly in the macro instance and applying the
   resulting arguments appropriately. 
     Example: (mymacro1 x ex y ey e) 
       is supposed to bind x in ey, y in ex, and x and y in e. 
       Translate it to 
	     (myproc1 (\y.ex) (\x.ey) (\xy.e)). 
       The procedure body depends on the transliteration of mymacro1. 
       If the above instance were to be expanded to
	     (let ((x \y.ex) (y \x.ey)) e)
       then myproc1 would be the function 
	     \px,py,pe. (pe px py).

   2. Consider the second use: the choice of a non-applicative order of
   evaluation of sub-expressions in a macro instance. Replace by using
   thunks for the sub-expressions, and apply when needed. 
     Example: (mymacro2 e1 e2 e3),
       when expanded, evaluates e2, if the result is 0, e1, 
       and otherwise e3. Translate this use to: 
	      (myproc2  \().e1 \().e2 \().e3)
       where myproc2 = \p1,p2,p3.if (zero? (p2)) (p1) (p2). 

   3. Consider the third use: implicit tagging. Tag explictly. I would
   almost claim that this use of macros is superfluous. We shouldn't think 
   of tags at all when we program: it's a confusion of identifiers and 
   symbols, which just happen to be in 1-1 correspondence. 

   4. Cosmetics: skip it. 				QEJ

QUESTION: Why do we use disciplined macros then, if (in Scheme) their
use can be reduced to the use of procedures? 

ANSWER: For syntactic reasons: disciplined macros abstract syntactic
patterns just like procedures abstract action patterns. 

WHY DO WE WANT TO HIDE PATTERNS: basically for psychological reasons,
but they are difficult to formalize. For example, 
	(let (x 1) fifty-lines-of-code)
is just much easier to comprehend than 
	((lambda (x) fifty-lines-of-code) 1).

>> Are there macro systems that let us only write good macros? No. 
A lot more research is needed. 

>> Are there procedural (sub)languages that let us only write good 
procedures? No. Ditto. 

For all the people interested in (disciplined) macros, I recommend the
following two dissertations:

[1] {Kohlbecker, E}.  {\it Syntactic Extensions in the Programming
    Language Lisp}.  Ph.D. dissertation, Indiana University, 1986.

[2] {Griffin, T.G}.  {\it Notational Definition and Top-Down
    Refinement for Interactive Proof Development Systems.} Ph.D.
    dissertation, Cornell University, 1988.

They are not text books on macros, but the former comes pretty close
(even if we know a little bit more now than extend-syntax and
hygiene).

-- Matthias Felleisen

P.S. When I coined the phrase "hygienic macros" in 86, I borrowed the
term from a paper by Barendregt on the lambda calculus who assumed
that readers can "hygienically" rename bound variables when neceesary.
The term specifically refers to the AUTOMATIC ENFORCEMENT OF LEXICAL
SCOPE FOR MACROS, and is inappropriate for characterising other
improvements of macro systems.

jeff@aiai.ed.ac.uk (Jeff Dalton) (03/11/91)

In article <1991Mar9.202550.10979@rice.edu> matthias@leto.rice.edu (Matthias Felleisen) writes:

>CLAIM: Disciplined uses of macros can be reduced to the uses of
>procedures. They are therefore as understandable (or even more so) as
>uses of procedures as far as their semantics is concerned.

>JUSTIFICATION OF CLAIM: It is easy to show that each use of a macro
>can be translated into the use of a procedure, with appropriate
>changes to instances of macros. 

This is an interesting claim and justification, especially since
it identifies a useful class of "disciplined" macros.

What the justification actually justifies, however, is that disciplined
uses of macros can be reduced to uses of procedures, not that macros
are therefore as understandable.

After all, it might be that the transformed code (ie, the code that
uses procedures instead of macros) was sometimes, or even always,
easier to understand.  Indeed, the reduction of macros to procedures
requires an additional step -- the transformation of the code -- which
could be seen as showing that macros are _harder_ to understand.

Moreover, I think the plausibility of your approach to this issue is
due in part to an accident of wording.  Someone said "macros are
harder to understand than procedures", but for their purposes they
could just as well have said "code that uses macros is harder to
understand than equivalent code that does not use macros".  And the
one could try the following:

CLAIM: Code that uses macros can be transformed into equivalent code
that does not use macros.  It is therefore as understandable ...

JUSTIFICATION: Expand the macro calls.

This approach will not be convincing to anyone who really does think
that the equivalent macro-less code is easier to understand.  It has
one defect that is avoided in your approach, namely that some macros
might be defined in such a way that calls to them cannot be completely
expanded.  But I don't think _that_ is why people find macros hard to
understand.  (If it is why, or at least a significant factor, then the
case for your approach would certainly be strengthened.)

In short. I think that in the end it still comes down to the difficult
to formalize psychological reasons you introduce later:

>QUESTION: Why do we use disciplined macros then, if (in Scheme) their
>use can be reduced to the use of procedures? 
>
>ANSWER: For syntactic reasons: disciplined macros abstract syntactic
>patterns just like procedures abstract action patterns. 
>
>WHY DO WE WANT TO HIDE PATTERNS: basically for psychological reasons,
>but they are difficult to formalize.

-- jd