From: Aaron Leung
Subject: Question about macro transformers...
Date: 
Message-ID: <LlYG7.28596$hZ.2646855@newsread2.prod.itd.earthlink.net>
Hi everyone,

    my understanding is that when you define a macro, you're essentially
defining a procedure which takes an S-expression representing the use of the
macro, and returns an S-expression representing the expansion; this
transformer-procedure is then called at compile-time to transform the source
program as necessary.

    My question is: how much of Common Lisp are you allowed to use in a
macro transformer?  Thanks for any info.

Best regards,
Aaron Leung

From: Kent M Pitman
Subject: Re: Question about macro transformers...
Date: 
Message-ID: <sfwbsiblhgi.fsf@shell01.TheWorld.com>
"Aaron Leung" <········@earthlink.net> writes:

> Hi everyone,
 
Hi.

>     my understanding is that when you define a macro, you're essentially
> defining a procedure which takes an S-expression representing the use of the
> macro, and returns an S-expression representing the expansion; this
> transformer-procedure is then called at compile-time to transform the source
> program as necessary.

Almost exactly right.

But not at compile-time.  At macro-expand-time.  The compiler does
macro expansion, but so does the interpreter.  (There was an important
Lisp dialect in the long distant past, Interlisp, that only had "compiler
macros", but not interpreter macros.  Its DWIM error-correction facility
would "fix your error" of using a macro in the interpreter by doing the
expansion for you as a "bug fix".  But this created other problems because
DWIM was supposed to be an optional facility that could be disabled, and
you couldn't disable it if you were relying on macros to work interpreted
and compiled.  CL learned form this and required interpreter and compiler
semantics to be effectively the same.)
 
I hope this subtlety makes sense.

>     My question is: how much of Common Lisp are you allowed to use in a
> macro transformer?  Thanks for any info.

The full language.

If you have user code you need, you have to sometimes arrange to load it
specially, since the default may be that supporting libraries are only
available at runtime. e.g.,


(load "my-support-file")
(defmacro foo () ...)
(defun bar () (foo ...))

will make my-support-file's functions available to bar to call, but not
available to foo at expansion time.  That's because toplevel forms do
not evaluate in "compile-time too" mode by default.  You can fix that by
doing:

(eval-when (:execute :compile-toplevel :load-toplevel)
  (load "my-support-file")) ;make available at compile and load time
(defmacro foo () ...)
(defun bar () (foo ...))

Now the support can be called either within FOO or within BAR.
From: Aaron Leung
Subject: Re: Question about macro transformers...
Date: 
Message-ID: <BHZG7.28103$S4.2537463@newsread1.prod.itd.earthlink.net>
Hi Kent,

    thanks for the reply.

"Kent M Pitman" <······@world.std.com> wrote in message
····················@shell01.TheWorld.com...
> Almost exactly right.
>
> But not at compile-time.  At macro-expand-time.  The compiler does
> macro expansion, but so does the interpreter. [...]

    Okay, I think I got it; macro expansion is a kind of pretreatment of the
source program, which conceptually takes place before the program is
evaluated or compiled.

> If you have user code you need, you have to sometimes arrange to load it
> specially, since the default may be that supporting libraries are only
> available at runtime. e.g.,
>
>
> (load "my-support-file")
> (defmacro foo () ...)
> (defun bar () (foo ...))
>
> will make my-support-file's functions available to bar to call, but not
> available to foo at expansion time.  That's because toplevel forms do
> not evaluate in "compile-time too" mode by default.  You can fix that by
> doing:
>
> (eval-when (:execute :compile-toplevel :load-toplevel)
>   (load "my-support-file")) ;make available at compile and load time
> (defmacro foo () ...)
> (defun bar () (foo ...))
>
> Now the support can be called either within FOO or within BAR.

    I'm afraid I don't know enough Common Lisp to grok all that (I'm just
reading about it out of interest).  Regarding what you said, I'm guessing
that it means that you generally can't arbitrarily use your own code in a
macro transformer unless you specifically tell the system about it.  Is that
right?

Best regards,
Aaron Leung
From: Kent M Pitman
Subject: Re: Question about macro transformers...
Date: 
Message-ID: <sfw8zdfxza0.fsf@shell01.TheWorld.com>
"Aaron Leung" <········@earthlink.net> writes:

>     I'm afraid I don't know enough Common Lisp to grok all that (I'm just
> reading about it out of interest).  Regarding what you said, I'm guessing
> that it means that you generally can't arbitrarily use your own code in a
> macro transformer unless you specifically tell the system about it.  Is that
> right?

To get the right stuff, you might want to look at CLHS
 http://www.xanalys.com/software_tools/reference/HyperSpec/FrontMatter/
and read the chapter on evaluation and compilation.

But basically, compilation is not intended to side-effect the compilation
environment so code that passes through the compiler getting compiled
is not ordinarily available to be called by code that runs in the compiler
(which includes macro expanders).  [Note that such code *is* available in
the interpreter because the interpreter macro-expansion environment is
generally the same as the interpreter execution environment.]  

For more info, see that chapter.  It really treats this in much more
precision than I have time to.  Plus my memory might make a mistake.
From: Kaz Kylheku
Subject: Re: Question about macro transformers...
Date: 
Message-ID: <TjZG7.30577$Ud.1241347@news1.rdc1.bc.home.com>
In article <······················@newsread2.prod.itd.earthlink.net>,
Aaron Leung wrote:
>Hi everyone,
>
>    my understanding is that when you define a macro, you're essentially
>defining a procedure which takes an S-expression representing the use of the
>macro, and returns an S-expression representing the expansion; this
>transformer-procedure is then called at compile-time to transform the source
>program as necessary.

Not quite. With modern Lisp macros, the input S-expression is destructured
for you, meaning that a match is performed between the form and the
macro's syntax, and its constituents are bound (unevaluated) to the
lambda variables.  In other words, the macro system itself already
performs a lot of useful gruntwork before your function takes control.

Nevertheless, the entire unevaluated macro form is available using
the lambda list keyword &whole, if you want to do your own processing
from scratch.

>    My question is: how much of Common Lisp are you allowed to use in a
>macro transformer?

The beauty is that the entire language is available to you, as in 
an ordinary function. So if you need to do complicated list processing,
for instance, all the functionality is there to support you.
From: Pierre R. Mai
Subject: Re: Question about macro transformers...
Date: 
Message-ID: <878zdfl7kd.fsf@orion.bln.pmsf.de>
···@ashi.footprints.net (Kaz Kylheku) writes:

> In article <······················@newsread2.prod.itd.earthlink.net>,
> Aaron Leung wrote:
> >Hi everyone,
> >
> >    my understanding is that when you define a macro, you're essentially
> >defining a procedure which takes an S-expression representing the use of the
> >macro, and returns an S-expression representing the expansion; this
> >transformer-procedure is then called at compile-time to transform the source
> >program as necessary.
> 
> Not quite. With modern Lisp macros, the input S-expression is destructured
> for you, meaning that a match is performed between the form and the
> macro's syntax, and its constituents are bound (unevaluated) to the
> lambda variables.  In other words, the macro system itself already
> performs a lot of useful gruntwork before your function takes control.

Actually, this isn't quite right either.  The expansion function
(which is what a "transformer-procedure" is really called in CL) is a
function of two arguments, the original form (s-expression if you
will) and an environment (which we'll ignore for the purposes of this
discussion).  It is invoked by the macro expansion facility
(via *macroexpand-hook*) and it returns the transformed form.

The automagic destructuring that defmacro provides for your own macros
actually happens inside the expansion function, which gets defined for
your macro, i.e. in principle defmacro could be defined as

(defmacro defmacro (name lambda-list &body body)
  `(setf (macro-function ',name)
         #'(lambda (%form %env)
             (block ,name
               (destructuring-bind ,lambda-list %form
                 ,@body)))))

Modulo compile-time effects via eval-when, handling of decls-and-doc,
other house-keeping-stuff, etc., etc.

> Nevertheless, the entire unevaluated macro form is available using
> the lambda list keyword &whole, if you want to do your own processing
> from scratch.

Since you are allowed to setf macro-function yourself, you can define
your own macros without using the defmacro facility at all, e.g.:

* (setf (macro-function 'qlist)
        (lambda (form env)
          (declare (ignore env))
          (list* 'list (mapcar (lambda (x) (list 'quote x)) (cdr form)))))

#<Interpreted Function (LAMBDA (FORM ENV) (DECLARE #) (LIST* 'LIST #))
  {48162451}>
* (macroexpand-1 '(qlist a b c d))

(LIST 'A 'B 'C 'D)
T
* (qlist a b c d)

(A B C D)

So people wishing for e.g. a hygienic pattern-matching macro facility
along the lines of Scheme or Dylan can define it quite nicely, like e.g.

(defmacro def-pattern-macro (name &rest pattern-clauses)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (setf (macro-function ',name)
           ,(calculate-transformer-lambda name pattern-clauses))))

(defun calculate-transformer-lambda (name pattern-clauses)
  ... do whatever it takes ...)

and then write

(def-pattern-macro my-if
  ((my-if <cond> <then>)
   (when <cond> <then>))
  ((my-if <cond> <then> <else>)
   (cond (<cond> <then>) (t <else>))))

Or whatever they want...

> >    My question is: how much of Common Lisp are you allowed to use in a
> >macro transformer?
> 
> The beauty is that the entire language is available to you, as in 
> an ordinary function. So if you need to do complicated list processing,
> for instance, all the functionality is there to support you.

Indeed!  And that same power is there to let you define macro-defining
macros, etc.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein