From: Jacek Generowicz
Subject: Macro expansion, times.
Date: 
Message-ID: <g0wv09cuvg.fsf@scumbag.ecs.soton.ac.uk>
On Lisp, p 101: "A macro call which occurs in a function definition
gets replaced by its expansion when the function is compiled".

Firstly, (though I guess that this is not all that important (not
specified by the standard?)) what happens when only the interpreter is
being used? It seems that implementations do not agree:

       CMUCL                         Clisp

* (defun two () (one))	    [1]> (defun two () (one))  
TWO			    TWO                        
* (defmacro one ()	    [2]> (defmacro one ()      
    '(print 'before))	           '(print 'before))   
ONE			    ONE                        
* (two)			    [3]> (two)                 
BEFORE			    BEFORE                     
BEFORE			    BEFORE                     
* (defmacro one ()	    [4]> (defmacro one ()      
    '(print 'after))	           '(print 'after))    
ONE			    ONE                        
* (two)			    [5]> (two)                 
BEFORE			    AFTER                      
BEFORE			    AFTER                      
* (defun two () (one))	    [6]>                       
TWO
* (two)
AFTER 
AFTER
* 

Secondly, what happens if the expansion is not invariant? 

(defun the-function (n)
  (do-complicated-stuff)
  (the-macro n)
  (more-complicated-stuff))

(defmacro the-macro (n)
  (some-expression-which-changes-as-a-function-of n))

Now the expansion is not available until run time, so presumably the
compiler must me invoked at run-time? . . . during each call to
the-function? (Surely not!)

CLtL2, p685: "If a function is of type compiled-function, then all
macro calls appearing lexically within the function have already been
expanded and will not be expanded again when the funtcion is called".

The only way I can accomodate this is by concluding that the-function
can never be of type compiled-function. I guess I am missing a couple
of lisp `times' and probably a few other concepts.

Elucidation and/or references welcome . . .

From: Steve Long
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <3C068D61.1A6EAF62@isomedia.com>
The defun macro defines a function; even when called from an interpreter,
the macro substitution is performed.

sl

Jacek Generowicz wrote:

> On Lisp, p 101: "A macro call which occurs in a function definition
> gets replaced by its expansion when the function is compiled".
>
> Firstly, (though I guess that this is not all that important (not
> specified by the standard?)) what happens when only the interpreter is
> being used? It seems that implementations do not agree:
>
>        CMUCL                         Clisp
>
> * (defun two () (one))      [1]> (defun two () (one))
> TWO                         TWO
> * (defmacro one ()          [2]> (defmacro one ()
>     '(print 'before))              '(print 'before))
> ONE                         ONE
> * (two)                     [3]> (two)
> BEFORE                      BEFORE
> BEFORE                      BEFORE
> * (defmacro one ()          [4]> (defmacro one ()
>     '(print 'after))               '(print 'after))
> ONE                         ONE
> * (two)                     [5]> (two)
> BEFORE                      AFTER
> BEFORE                      AFTER
> * (defun two () (one))      [6]>
> TWO
> * (two)
> AFTER
> AFTER
> *
>
> Secondly, what happens if the expansion is not invariant?
>
> (defun the-function (n)
>   (do-complicated-stuff)
>   (the-macro n)
>   (more-complicated-stuff))
>
> (defmacro the-macro (n)
>   (some-expression-which-changes-as-a-function-of n))
>
> Now the expansion is not available until run time, so presumably the
> compiler must me invoked at run-time? . . . during each call to
> the-function? (Surely not!)
>
> CLtL2, p685: "If a function is of type compiled-function, then all
> macro calls appearing lexically within the function have already been
> expanded and will not be expanded again when the funtcion is called".
>
> The only way I can accomodate this is by concluding that the-function
> can never be of type compiled-function. I guess I am missing a couple
> of lisp `times' and probably a few other concepts.
>
> Elucidation and/or references welcome . . .
From: Thomas F. Burdick
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <xcvitbtfgbc.fsf@conquest.OCF.Berkeley.EDU>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> On Lisp, p 101: "A macro call which occurs in a function definition
> gets replaced by its expansion when the function is compiled".
> 
> Firstly, (though I guess that this is not all that important (not
> specified by the standard?)) what happens when only the interpreter is
> being used? It seems that implementations do not agree:

Well, "On Lisp" isn't the standard.  The standard is available on the
web -- it's called "The Common Lisp HyperSpec".

For compiled code, the macros are all expanded.  For interpreted code,
the macros are all expanded at some point before the code is
evaluated.  For CLISP, this means just before.  CMUCL does partial
compilation of most things you type into the toplevel because it
doesn't come with much of an interpreter.  Both behaviors are allowed.
It's even acceptable to have no interpreter whatsoever
[think (defun eval (form) (funcall (compile nil (list 'lambda () form)))) ]

> Secondly, what happens if the expansion is not invariant? 
> 
> (defun the-function (n)
>   (do-complicated-stuff)
>   (the-macro n)
>   (more-complicated-stuff))
> 
> (defmacro the-macro (n)
>   (some-expression-which-changes-as-a-function-of n))
> 
> Now the expansion is not available until run time, so presumably the
> compiler must me invoked at run-time? . . . during each call to
> the-function? (Surely not!)

You're misunderstanding macros.  What you want the-macro to do is to
behave exactly like a function call.  The call to THE-MACRO in
THE-FUNCTION will recieve the symbol N as its argument.  Because
macroexpansion time happens before THE-FUNCTION is evaluated, the
macro cannot see the value of the variable N.  Think of it as a way to
programatically do source-to-source transformations.

(defmacro foo (form)
  (if (eql form 2)
      '(princ "Always two")
      `(progn
         (princ "It evaluated to ")
         (princ (if (eql ,form 2) "two" "not two")))))

(macroexpand '(foo 2))
  => (princ "Always two")
(macroexpand '(foo (+ 1 1)))
  => (progn
       (princ "It evaluated to ")
       (princ (if (eql (+ 1 1) 2) "two" "not two")))

> CLtL2, p685: "If a function is of type compiled-function, then all
> macro calls appearing lexically within the function have already been
> expanded and will not be expanded again when the funtcion is called".
> 
> The only way I can accomodate this is by concluding that the-function
> can never be of type compiled-function. I guess I am missing a couple
> of lisp `times' and probably a few other concepts.
> 
> Elucidation and/or references welcome . . .

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0g06x3xhx.fsf@scumbag.ecs.soton.ac.uk>
Thomas F. Burdick <···@conquest.OCF.Berkeley.EDU> writes:

> You're misunderstanding macros. 

Undoubtedly.

> What you want the-macro to do is to behave exactly like a function
> call.

Not exactly. I want it to create some source code which is then
evaluated. Hmm, I guess that's `exactly like a function' plus a bit
more.

> The call to THE-MACRO in THE-FUNCTION will recieve the symbol N as
> its argument.  Because macroexpansion time happens before
> THE-FUNCTION is evaluated, the macro cannot see the value of the
> variable N.

Yes, I'm beginning to grasp this point.

> Think of it as a way to programatically do source-to-source
> transformations.

I do . . . it's just that the transformations I wanted were a little
too ambitious :-)

Is there a way to do what I want? which is the following.

I have a function which calculates a set of values. The number of
values and the way they are calculated changes with the spatial
dimension in which I am working, but there is a clear pattern. So in
1D I need to calculate something of the form

   (prog
    (setf a (fn x))
    (setf b (fn 1)))

in 2D

   (prog
    (setf a (fn x y))
    (setf b (fn 1 y))
    (setf c (fn x 1)))

in 3D

   (prog
    (setf a (fn x y z))
    (setf b (fn 1 y z))
    (setf c (fn x 1 z))
    (setf d (fn x y 1)))

and so on . . .

I want to have just one function which can deal with any (integer)
dimension. I know it can be done because I have implemented it in
other languages, but I was hoping that macros would help me do it more
neatly/easily/concisely/transparently.
From: Thomas F. Burdick
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <xcv3d2whos8.fsf@conquest.OCF.Berkeley.EDU>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> Thomas F. Burdick <···@conquest.OCF.Berkeley.EDU> writes:
> 
> > You're misunderstanding macros. 
> 
> Undoubtedly.
> 
> > What you want the-macro to do is to behave exactly like a function
> > call.
> 
> Not exactly. I want it to create some source code which is then
> evaluated. Hmm, I guess that's `exactly like a function' plus a bit
> more.

Well, the only difference between this and a normal function call is
that the former will capture any lexical bindings -- a function call
that magically transports you back to the world of dynamic binding :-)

> > The call to THE-MACRO in THE-FUNCTION will recieve the symbol N as
> > its argument.  Because macroexpansion time happens before
> > THE-FUNCTION is evaluated, the macro cannot see the value of the
> > variable N.
> 
> Yes, I'm beginning to grasp this point.
> 
> > Think of it as a way to programatically do source-to-source
> > transformations.
> 
> I do . . . it's just that the transformations I wanted were a little
> too ambitious :-)

The thing with source-to-source transformations, is that they can't
depend on run-tiome values (unless the value is constant).  I don't
understand exactly what you want, so you'll have to explain it more
fully.  I'm guessing you could do it with higher-order functions &/or
macros.

 [...]

> I want to have just one function which can deal with any (integer)
> dimension. I know it can be done because I have implemented it in
> other languages, but I was hoping that macros would help me do it more
> neatly/easily/concisely/transparently.

Out of curiosity, what language(s) do you normally use?  This is
sometimes useful to know for figuring out what misconceptions people
may have about CL.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kent M Pitman
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <sfwofll2dgj.fsf@shell01.TheWorld.com>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> Thomas F. Burdick <···@conquest.OCF.Berkeley.EDU> writes:
> 
> > You're misunderstanding macros. 
> 
> Undoubtedly.
> 
> > What you want the-macro to do is to behave exactly like a function
> > call.
> 
> Not exactly. I want it to create some source code which is then
> evaluated. Hmm, I guess that's `exactly like a function' plus a bit
> more.
> 
> > The call to THE-MACRO in THE-FUNCTION will recieve the symbol N as
> > its argument.  Because macroexpansion time happens before
> > THE-FUNCTION is evaluated, the macro cannot see the value of the
> > variable N.
> 
> Yes, I'm beginning to grasp this point.
> 
> > Think of it as a way to programatically do source-to-source
> > transformations.
> 
> I do . . . it's just that the transformations I wanted were a little
> too ambitious :-)
> 
> Is there a way to do what I want? which is the following.
> 
> I have a function which calculates a set of values. The number of
> values and the way they are calculated changes with the spatial
> dimension in which I am working, but there is a clear pattern. So in
> 1D I need to calculate something of the form
> 
>    (prog
>     (setf a (fn x))
>     (setf b (fn 1)))
> 
> in 2D
> 
>    (prog
>     (setf a (fn x y))
>     (setf b (fn 1 y))
>     (setf c (fn x 1)))
> 
> in 3D
> 
>    (prog
>     (setf a (fn x y z))
>     (setf b (fn 1 y z))
>     (setf c (fn x 1 z))
>     (setf d (fn x y 1)))
> 
> and so on . . .
> 
> I want to have just one function which can deal with any (integer)
> dimension. I know it can be done because I have implemented it in
> other languages, but I was hoping that macros would help me do it more
> neatly/easily/concisely/transparently.

You can do what you want but no one can show you how without you
showing the input form to which you want the outptu form to expand.
The reason this is important is that if a macro expands into a bunch
of assignments to variables, it needs to be well-understood whether the
specific names a, b,c, are wired into your program, which I don't
recommend.  If they are, you need to say what happens after Z.  If I recall
right, Dr. Seuss in On Beyond Zebra says "Yuzz" comes next, but I don't 
know its unicode. 

You can't have a macro that expands into all possible expansions because
then it will take infinite time to compile.

If you want it to take a variable number of args and compute a variable
number of results, you wouldn't use a macro.  You'd probably just have
a function that takes a list of n arguments and returns n+1 values as a
list.  That's easy to do with no macros.

Btw, you want progn, not prog.
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0k7w8v1rf.fsf@scumbag.ecs.soton.ac.uk>
Kent M Pitman <······@world.std.com> writes:

> You can do what you want but no one can show you how without you
> showing the input form to which you want the outptu form to expand.

OK, what I was really trying is this (forgive minor mistakes, I don't
have access to the code at the moment):

(calc-coefs 1) =>

   (dotimes (i 2)
     (setf (aref c 0 i)
   	   (sum (j 0 1)
   		(* (epsilon i j) (aref x 0 j))))
     (setf (aref c 1 i)
   	   (sum (j 0 1)
   		(* (epsilon i j) 1))))
   
(calc-coefs 2) =>

   (dotimes (i 3)
     (setf (aref c 0 i)
   	   (sum (j 0 2) (k 0 2)
   		(* (epsilon i j k) (aref x 0 j) (aref x 1 k))))
     (setf (aref c 1 i)
   	   (sum (j 0 2) (k 0 2)
   		(* (epsilon i j k) 1            (aref x 1 k))))
     (setf (aref c 2 i)
   	   (sum (j 0 2) (k 0 2)
   		(* (epsilon i j k) (aref x 0 j) 1))))
   
etc.

> The reason this is important is that if a macro expands into a bunch
> of assignments to variables, it needs to be well-understood whether the
> specific names a, b,c, are wired into your program,

c and x are locally bound by an enclosing let; i,j,k... are just dummy
indices so can be called whatever you like, but initially hard wired
to assist legibility during debugging.

> You can't have a macro that expands into all possible expansions because
> then it will take infinite time to compile.

Now that I understand that macroexpansion is finished once and for all
before run-time, this is obvious.

> Btw, you want progn, not prog.

Ta.
From: Marco Antoniotti
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <y6csnawqpcz.fsf@octagon.mrl.nyu.edu>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > You can do what you want but no one can show you how without you
> > showing the input form to which you want the outptu form to expand.
> 
> OK, what I was really trying is this (forgive minor mistakes, I don't
> have access to the code at the moment):
> 
> (calc-coefs 1) =>
> 
>    (dotimes (i 2)
>      (setf (aref c 0 i)
>    	   (sum (j 0 1)
>    		(* (epsilon i j) (aref x 0 j))))
>      (setf (aref c 1 i)
>    	   (sum (j 0 1)
>    		(* (epsilon i j) 1))))
>    
> (calc-coefs 2) =>
> 
>    (dotimes (i 3)
>      (setf (aref c 0 i)
>    	   (sum (j 0 2) (k 0 2)
>    		(* (epsilon i j k) (aref x 0 j) (aref x 1 k))))
>      (setf (aref c 1 i)
>    	   (sum (j 0 2) (k 0 2)
>    		(* (epsilon i j k) 1            (aref x 1 k))))
>      (setf (aref c 2 i)
>    	   (sum (j 0 2) (k 0 2)
>    		(* (epsilon i j k) (aref x 0 j) 1))))
>    
> etc.
> 
> > The reason this is important is that if a macro expands into a bunch
> > of assignments to variables, it needs to be well-understood whether the
> > specific names a, b,c, are wired into your program,
> 
> c and x are locally bound by an enclosing let; i,j,k... are just dummy
> indices so can be called whatever you like, but initially hard wired
> to assist legibility during debugging.

This is still bad practice (IMHO).  It would still be better for your
macro to be called as

	(calc-coefs 2 c x)

Of course, assuming

	(sum (j 0 2) (k 0 2) (* (epsilon i j k) (aref x 0 j) 1))))

is equivalent

	(let (($acc 0))
          (dotimes (j 2 $acc)
             (dotimes (k 2)
                (incf $acc (* (epsilon i j k) (aref x 0 j) 1)))))

(Sorry, I did jump in late...)

Cheers


-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Tim Bradshaw
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <fbc0f5d1.0111301114.76bceeb1@posting.google.com>
Jacek Generowicz <···@ecs.soton.ac.uk> wrote in message news:<··············@scumbag.ecs.soton.ac.uk>...
> 
> (calc-coefs 1) =>
> 
>    (dotimes (i 2)
>      (setf (aref c 0 i)
>    	   (sum (j 0 1)
>    		(* (epsilon i j) (aref x 0 j))))
>      (setf (aref c 1 i)
>    	   (sum (j 0 1)
>    		(* (epsilon i j) 1))))
>    
> (calc-coefs 2) =>
> 
>    (dotimes (i 3)
>      (setf (aref c 0 i)
>    	   (sum (j 0 2) (k 0 2)
>    		(* (epsilon i j k) (aref x 0 j) (aref x 1 k))))
>      (setf (aref c 1 i)
>    	   (sum (j 0 2) (k 0 2)
>    		(* (epsilon i j k) 1            (aref x 1 k))))
>      (setf (aref c 2 i)
>    	   (sum (j 0 2) (k 0 2)
>    		(* (epsilon i j k) (aref x 0 j) 1))))
>    

I think what you want is compiler macros.  I don't understand your
code (all those unbound variables look worrying), but here is an
example for a function, ZEROIFY-SOME, which zeros some rows in an
array.  The compiler macro checks to see if the number of rows to zero
is known at compile-time and in that case inlines an appropriate
unrolled loop.

(defun zeroify-some (a n)
  ;; Zero the first N rows of A
  (dotimes (i n)
    (dotimes (j (array-dimension a 1))
      (setf (aref a i j) 0)))
  a)

(define-compiler-macro zeroify-some (&whole form
                                            a n)
  ;; If N is a compile-time constant we can optimize this.
  (if (typep n '(integer 0))
      ;; This is actually safe - no point in gensyms because we know
everything
      ;; about the code in here.
      `(let* ((a ,a)
              (ad0 (array-dimension a 0)))
         ,@(loop for i from 0 below n
                 collect
                 `(dotimes (j ad0)
                    (setf (aref a ,i j) 0)))
         a)
    ;; Else punt.
    form))

You mentioned in another article that you'd given up on the relevant
chapter in the CLHS after half an hour.  That's a bad move: if you
want to do the kind of things that macros and compiler macros let you
do then you need to read *the spec* really carefully.  This stuff
isn't trivial to understand (hey, it's not even *available* in
practically any language other than CL), and if you want to do it you
need to put in the work to understand it.  Asking questions about
advanced topics while not having RTFMd about them, and then declining
to do so when pointed at it is a really good way to get people upset
at you on cll

--tim
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0k7w7dpvb.fsf@scumbag.ecs.soton.ac.uk>
··········@tfeb.org (Tim Bradshaw) writes:

> Jacek Generowicz <···@ecs.soton.ac.uk> wrote:
> > 
> > (calc-coefs 1) =>
> > 
> >    (dotimes (i 2)
> >      (setf (aref c 0 i)
> >          (sum (j 0 1)
> >               (* (epsilon i j) (aref x 0 j))))
> >      (setf (aref c 1 i)
> >          (sum (j 0 1)
> >               (* (epsilon i j) 1))))

 
> I think what you want is compiler macros.  I don't understand your
> code (all those unbound variables look worrying),

(sum (j 0 2) expression) in the equivalent of (in TeX notation) 
\Sigma_{j=0}^2 expression  or, in words, "the sum of expression over j
ranging from 0 through 2", and hence expands to something like 
(loop for j from 0 to 2 sum expression). As stated, x and c are bound
in the enclosing form.

> but here is an example for a function, ZEROIFY-SOME, which zeros
> some rows in an array.  The compiler macro checks to see if the
> number of rows to zero is known at compile-time and in that case
> inlines an appropriate unrolled loop.
> 
> (defun zeroify-some (a n)
>   ;; Zero the first N rows of A
>   (dotimes (i n)
>     (dotimes (j (array-dimension a 1))
>	(setf (aref a i j) 0)))
>   a)
> 
> (define-compiler-macro zeroify-some (&whole form
>					      a n)
>   ;; If N is a compile-time constant we can optimize this.
>   (if (typep n '(integer 0))
>	;; This is actually safe - no point in gensyms because we know
> everything
>	;; about the code in here.
>	`(let* ((a ,a)
>		(ad0 (array-dimension a 0)))
>	   ,@(loop for i from 0 below n
>		   collect
>		   `(dotimes (j ad0)
>		      (setf (aref a ,i j) 0)))
>	   a)
>     ;; Else punt.
>     form))

No, the whole source of my confusion was some wild expectation of the
macro being able to deal with different runtime Ns. I'll go away and
read about compiler macros to make sure I'm not missing the point,
though.

> You mentioned in another article that you'd given up on the relevant
> chapter in the CLHS after half an hour.

In the very same article I explicitly stated that I had NOT given up
on the chapter.

> That's a bad move: if you want to do the kind of things that macros
> and compiler macros let you do then you need to read *the spec*
> really carefully.

Which, as stated in the same article, I fully intend to do. 

Every now and then I get some daft idea into my head, which needs
dislodging. It usually takes a small observation by someone else. In
this case a couple of people pointed out that in the example I cited
the macro would be passed the symbol n rather than a number as I was
expecting (for reasons which I myself can't quite fathom in
retrospect). In the short term, this was infinitely more constructive
than reading the spec. In the long term, I fully appreciate that the
spec in the way to Nirvana, and it is the route I intend to follow.

> This stuff isn't trivial to understand (hey, it's not even
> *available* in practically any language other than CL), and if you
> want to do it you need to put in the work to understand it.  Asking
> questions about advanced topics while not having RTFMd about them,
> and then declining to do so when pointed at it is a really good way
> to get people upset at you on cll

I totally agree. I submit that stating that one finds TFM a tad
impenetrable in not the same as declining to R it.
From: Marco Antoniotti
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <y6celmeby68.fsf@octagon.mrl.nyu.edu>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> ··········@tfeb.org (Tim Bradshaw) writes:
> 
> > Jacek Generowicz <···@ecs.soton.ac.uk> wrote:
> > > 
> > > (calc-coefs 1) =>
> > > 
> > >    (dotimes (i 2)
> > >      (setf (aref c 0 i)
> > >          (sum (j 0 1)
> > >               (* (epsilon i j) (aref x 0 j))))
> > >      (setf (aref c 1 i)
> > >          (sum (j 0 1)
> > >               (* (epsilon i j) 1))))
> 
>  
> > I think what you want is compiler macros.  I don't understand your
> > code (all those unbound variables look worrying),
> 
> (sum (j 0 2) expression) in the equivalent of (in TeX notation) 
> \Sigma_{j=0}^2 expression  or, in words, "the sum of expression over j
> ranging from 0 through 2", and hence expands to something like 
> (loop for j from 0 to 2 sum expression). As stated, x and c are bound
> in the enclosing form.

Then it'd be better to use MACROLET to clearly mark the enclosing
scope.  IMHO you should not use DEFMACRO to construct forms with free
variables.

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0vgfqwrau.fsf@scumbag.ecs.soton.ac.uk>
Elsewhere in the thread Marco Antoniotti <·······@cs.nyu.edu> wrote:

> > c and x are locally bound by an enclosing let; i,j,k... are just
> > dummy indices so can be called whatever you like, but initially hard
> > wired to assist legibility during debugging.
> 
> This is still bad practice (IMHO).  It would still be better for your
> macro to be called as
> 
> 	  (calc-coefs 2 c x)

Here he re-iterates:

> > > Jacek Generowicz <···@ecs.soton.ac.uk> wrote:
> > > > 
> > > > (calc-coefs 1) =>
> > > > 
> > > >    (dotimes (i 2)
> > > >      (setf (aref c 0 i)
> > > >          (sum (j 0 1)
> > > >               (* (epsilon i j) (aref x 0 j))))
> > > >      (setf (aref c 1 i)
> > > >          (sum (j 0 1)
> > > >               (* (epsilon i j) 1))))
> > 
> >  
> > > I think what you want is compiler macros.  I don't understand your
> > > code (all those unbound variables look worrying),
> > 
> > (sum (j 0 2) expression) in the equivalent of (in TeX notation) 
> > \Sigma_{j=0}^2 expression  or, in words, "the sum of expression over j
> > ranging from 0 through 2", and hence expands to something like 
> > (loop for j from 0 to 2 sum expression). As stated, x and c are bound
> > in the enclosing form.
> 
> Then it'd be better to use MACROLET to clearly mark the enclosing
> scope.  IMHO you should not use DEFMACRO to construct forms with free
> variables.

(Sorry, I'm slowly catching up with various strands of the thread)

Yes, good observation, thank you.
From: Ole Rohne
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <ebwbshkzhd3.fsf@lxplus045.cern.ch>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> The number of values and the way they are calculated changes with
> the spatial dimension in which I am working, but there is a clear
> pattern.

I probably shouldn't stick my head out with this gross hack of mine...
However, it is somewhat related to your problem and might give you
some ideas - and me some useful feedback:

I have a function:

(defun make-matrix-inversion (name dimension)
   "Return open coded matrix inversion" ...)

that basically calls maxima (aka macsyma) routines ($optimize ($invert
($matrix ...)))  and rearranges the output into something that looks
like the CL source for an open-coded nxn matrix inversion:

* (pprint (maxima::make-matrix-inversion 'test 2))
(TEST (ARRAY) "Invert 2x2 matrix"
 (DECLARE (TYPE (SIMPLE-ARRAY DOUBLE-FLOAT (2 2)) ARRAY)
          (OPTIMIZE (SPEED 3) (SAFETY 0) (SPACE 0)))
 (LET
  (($%M-0-0 (AREF ARRAY 0 0)) ($%M-0-1 (AREF ARRAY 0 1))
   ($%M-1-0 (AREF ARRAY 1 0)) ($%M-1-1 (AREF ARRAY 1 1)))
  (LET* ((#:$%1 (/ 1 (+ (* -1 $%M-0-1 $%M-1-0) (* $%M-0-0 $%M-1-1)))))
        (SETF (AREF ARRAY 0 0) (* $%M-1-1 #:$%1))
        (SETF (AREF ARRAY 0 1) (* -1 $%M-0-1 #:$%1))
        (SETF (AREF ARRAY 1 0) (* -1 $%M-1-0 #:$%1))
        (SETF (AREF ARRAY 1 1) (* $%M-0-0 #:$%1))))
 ARRAY)

* (pprint (maxima::make-matrix-inversion 'test 5))
(output omitted in the public interest :-)

Now my macro definition is simply,

(defmacro define-matrix-inversion
  (name dimension &key (element-type 'double-float))
  "DEFUN open coded matrix inversion"
  `(defun ,@(make-matrix-inversion name dimension :element-type element-type))),

allowing me to (define-matrix-inversion invert-3x3 3) and
(define-matrix-inversion invert-4x4 4) to get functions named
invert-3x3 and invert-4x4 that inverts matrices that are precisely 3x3
and 4x4. If I wanted functions that would invert matrices of any
dimensions, this is clearly not the way to go...

This just happens to be what I need for my next gross hack, a similar
function/macro combination that generates least squares fitting
functions doing symbolic differentiation etc.

	Ole
From: Kent M Pitman
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <sfwy9kpuxfc.fsf@shell01.TheWorld.com>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> On Lisp, p 101: "A macro call which occurs in a function definition
> gets replaced by its expansion when the function is compiled".
> 
> Firstly, (though I guess that this is not all that important (not
> specified by the standard?)) what happens when only the interpreter is
> being used? It seems that implementations do not agree:
> 

whether it's in a function definition or not is irrelevant.

compilation is also irrelevant. macro expansion time is relevant.

all you can know of macro expansion time is that it happens before
execution time, and it is forced by compilation.  it may be forced as well
by executing a definition in the interpreter, or it may be deferred until
execution.  

> Secondly, what happens if the expansion is not invariant? 

This example below doesn't capture the meaning I take you to have by
this question.  If an expansion is not invariant, that's irrelevant.
The definition available when the expander runs  is what's used.
It's not obvious at all to me what the do-complicated-stuff or
more-complicated-stuff has to do with anything here below.  The
forward reference to the-macro is an error and will almost surely lose
very badly in all implementations.

> (defun the-function (n)
>   (do-complicated-stuff)
>   (the-macro n)
>   (more-complicated-stuff))
> 
> (defmacro the-macro (n)
>   (some-expression-which-changes-as-a-function-of n))
> 
> Now the expansion is not available until run time, so presumably the
> compiler must me invoked at run-time?

No.

> . . . during each call to
> the-function? (Surely not!)

[That can happen in some interpreters, but I think most cache expansions.]

Macro definitions must be available at compile time.

Compilation is required to do all macro expansion.

The interpreter is permitted (but not required) to delay macro
expansion until it occurs.  If macro redefinition occurs between calls
to different branches of the same function, there is no consistency
requirement in the interpreter.  In general, if you redefine a macro
you must recompile or at least reexecute all definitions that depend
on the macro or you are not guaranteed to be safe.

> CLtL2, p685: "If a function is of type compiled-function, then all
> macro calls appearing lexically within the function have already been
> expanded and will not be expanded again when the funtcion is called".

CLTL2 is not a proper reference to the language.

It's ok to use casually, but don't assume everything it says is right.
CLHS is the right reference to use
http://www.xanalys.com/software_tools/reference/HyperSpec/FrontMatter/
You can download it from 
http://www.xanalys.com/software_tools/reference/HyperSpec/
if you are using it a lot and want faster access.

> The only way I can accomodate this is by concluding that the-function
> can never be of type compiled-function.

Consider the (likely) possibility that the-function will be
incorrectly compiled thinking it is a function call, and that you will
lose utterly as a result of that.

> I guess I am missing a couple
> of lisp `times' and probably a few other concepts.

Yes.  Read the section on evaluation and compilation in CLHS.
 
> Elucidation and/or references welcome . . .

CLHS.
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0itbt3xoe.fsf@scumbag.ecs.soton.ac.uk>
Kent M Pitman <······@world.std.com> writes:

> It's not obvious at all to me what the do-complicated-stuff or
> more-complicated-stuff has to do with anything here below.

I'm sorry, it's completely irrelevant, something that got overlooked
it the cull.

> The forward reference to the-macro is an error and will almost
> surely lose very badly in all implementations.

Yup. Though it's good to be reminded.

> > (defun the-function (n)
> >   (do-complicated-stuff)
> >   (the-macro n)
> >   (more-complicated-stuff))
> > 
> > (defmacro the-macro (n)
> >   (some-expression-which-changes-as-a-function-of n))
> > 
> > Now the expansion is not available until run time, so presumably
> > the compiler must me invoked at run-time?

> Compilation is required to do all macro expansion.

This means

a) Only compilation is allowed to expand macros.

b) It is not guaranteed that all macro expansion has been performed
   until compilation has taken place.

c) Other . . .

?

> CLTL2 is not a proper reference to the language.
> 
> It's ok to use casually, but don't assume everything it says is
> right.
> CLHS is the right reference to use
> http://www.xanalys.com/software_tools/reference/HyperSpec/FrontMatter/
> You can download it from 
> http://www.xanalys.com/software_tools/reference/HyperSpec/
> if you are using it a lot and want faster access.

I have it, thanks (and thank you for creating it and making it
available). I do find it a bit terse (aka unhelpful) at times,
though. I didn't really strike gold with it in this case.

> > The only way I can accomodate this is by concluding that
> > the-function
> > can never be of type compiled-function.
> 
> Consider the (likely) possibility that the-function will be
> incorrectly compiled thinking it is a function call, and that you
> will lose utterly as a result of that.

I even have practical evidence of it, though this diagnosis of the
problem was not one that sprang to my mind immediately.

> > I guess I am missing a couple
> > of lisp `times' and probably a few other concepts.
> 
> Yes.  Read the section on evaluation and compilation in CLHS.

I have just perused it. I don't feel enlightened. I think CLHS is
great as a reference, but I have great difficulty in using it to learn
any concepts. I think you have to have a fair idea of what it is that
you are looking up, to be able to profit from it. In this particular
case I am just far too lost.

> > Elucidation and/or references welcome . . .
> 
> CLHS.

OK, I promise to burn all my lisp books and henceforth only look to
the one and only true reference :-)
From: Kent M Pitman
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <sfwr8qh2dqk.fsf@shell01.TheWorld.com>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > It's not obvious at all to me what the do-complicated-stuff or
> > more-complicated-stuff has to do with anything here below.
> 
> I'm sorry, it's completely irrelevant, something that got overlooked
> it the cull.
> 
> > The forward reference to the-macro is an error and will almost
> > surely lose very badly in all implementations.
> 
> Yup. Though it's good to be reminded.
> 
> > > (defun the-function (n)
> > >   (do-complicated-stuff)
> > >   (the-macro n)
> > >   (more-complicated-stuff))
> > > 
> > > (defmacro the-macro (n)
> > >   (some-expression-which-changes-as-a-function-of n))
> > > 
> > > Now the expansion is not available until run time, so presumably
> > > the compiler must me invoked at run-time?
> 
> > Compilation is required to do all macro expansion.
> 
> This means
> 
> a) Only compilation is allowed to expand macros.
> 
> b) It is not guaranteed that all macro expansion has been performed
>    until compilation has taken place.
> 
> c) Other . . .

(c) Expansion  is forced by either compilation or execution, but it may be
done at various implementation-determined times prior.

You asked for the reference and I gave it to you.
It should have answered this.

> > CLTL2 is not a proper reference to the language.
> > 
> > It's ok to use casually, but don't assume everything it says is
> > right.
> > CLHS is the right reference to use
> > http://www.xanalys.com/software_tools/reference/HyperSpec/FrontMatter/
> > You can download it from 
> > http://www.xanalys.com/software_tools/reference/HyperSpec/
> > if you are using it a lot and want faster access.
> 
> I have it, thanks (and thank you for creating it and making it
> available). I do find it a bit terse (aka unhelpful) at times,
> though. I didn't really strike gold with it in this case.

Then find a text that describe the language you are using. CLTL2 does not.

> > > The only way I can accomodate this is by concluding that
> > > the-function
> > > can never be of type compiled-function.
> > 
> > Consider the (likely) possibility that the-function will be
> > incorrectly compiled thinking it is a function call, and that you
> > will lose utterly as a result of that.
> 
> I even have practical evidence of it, though this diagnosis of the
> problem was not one that sprang to my mind immediately.

Surely it works the same in all other languages that use macro preprocessing.
Macros have to precede use.  I don't know any language where this is not
so.
 
> > > I guess I am missing a couple
> > > of lisp `times' and probably a few other concepts.
> > 
> > Yes.  Read the section on evaluation and compilation in CLHS.
> 
> I have just perused it. I don't feel enlightened. I think CLHS is
> great as a reference, but I have great difficulty in using it to learn
> any concepts. I think you have to have a fair idea of what it is that
> you are looking up, to be able to profit from it. In this particular
> case I am just far too lost.

I didn't suggest you peruse it.  I suggested you read the entire chapter
linearly and in detail.  I know of very few texts that cover this,tersely
or otherwise.

> > > Elucidation and/or references welcome . . .
> > 
> > CLHS.
> 
> OK, I promise to burn all my lisp books and henceforth only look to
> the one and only true reference :-)

I didn't say that.  Use whatever book you like if you find one that is
more to your liking.  But use one that describes the language as defined.
CLTL2 is not a reference to ANSI CL.  It was, as explained in the prface,
pages xiv to xv if memory serves, a snapshot of work in progress. It was
not created or reviewed by any committee (unlike CLTL, which was).
Things were added to and retracted from the language prior to its being
finished, and Steele did not coordinate the content with the committee.
It may be a fun read, but it is not something I care to answer to or
defend.

At least CLTL, though smaller and also superseded, was a committee project.

But the fact is that I am not confident that the text in CLTL2 means the
same thing, and so any confusions or questions you get as a result might
be due to incompleteness, things that have changed, clerical errors, or
something else.

Again, I am not trying to say CLHS is the only thing you should read.
I am not trying to be defensive about the spec.  It certainly leaves some
things vague.  People have said enough good things about it that I don't
fear them saying bad things.  Heck, I even say bad things about it.  It is
an engineering work that is "as good as it could get given time limitations
I was under" and the fact that it was me and not someone else doing it.
But, like it or not, it *is* the langauge definition and when you are being
confused on fine details, looking at something that is not the language
definition is fine to "enlighten" you ... but if you fail to be enlightened,
you should not confuse the book (an individual's presentation) with the
language.  If you try to have a discussion of both at the same time, you
will create even more confusion for yourself.
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0n114v3nb.fsf@scumbag.ecs.soton.ac.uk>
Kent M Pitman <······@world.std.com> writes:

> > > Yes.  Read the section on evaluation and compilation in CLHS.
> > 
> > I have just perused it. I don't feel enlightened. I think CLHS is
> > great as a reference, but I have great difficulty in using it to learn
> > any concepts. I think you have to have a fair idea of what it is that
> > you are looking up, to be able to profit from it. In this particular
> > case I am just far too lost.
> 
> I didn't suggest you peruse it.  I suggested you read the entire chapter
> linearly and in detail.

That is exactly how I started and continued for about half an hour. Not
having learned anything that seemed to be directly relevant after this
time, I looked through the rest much more quickly, coming to the
conclusion that if I were to finish reading and inwardly digesting the
section before trying to get input by other means, then I would not
get to resolve my misunderstanding for man-months yet. The proportion
of my time I can afford to spend on lisp makes this an un-viable
option. As one who considers his time to be his most valuable
commodity, I hope you will find some sympathy for my position.

That does not mean to say that I have given up on it. I fully intend
to return to it, again and again, it's just that, well, (a) life goes
on (b) other input might help me make better progress.

> > OK, I promise to burn all my lisp books and henceforth only look to
> > the one and only true reference :-)
> 
> I didn't say that.

I'm not a great fan of smileys, but I inserted the one above precisely
to avoid being interpreted in this way.

> Use whatever book you like if you find one that is
> more to your liking.  But use one that describes the language as defined.

Does such a thing exist, in your opinion ?

> Again, I am not trying to say CLHS is the only thing you should read.
> I am not trying to be defensive about the spec.  It certainly leaves some
> things vague.  People have said enough good things about it that I don't
> fear them saying bad things.

Just to be absolutely clear, I find CLHS very useful and am very
grateful to you for it.

> But, like it or not, it *is* the langauge definition and when you are being
> confused on fine details, looking at something that is not the language
> definition is fine to "enlighten" you ... but if you fail to be enlightened,
> you should not confuse the book (an individual's presentation) with the
> language.

I am not confusing the two, though I am (perhaps naively) working on
the assumption that there is a strong correlation between them.

> If you try to have a discussion of both at the same time, you
> will create even more confusion for yourself.

I disagree. I think one can productively discuss people's
interpretations of the beast while relying on the definition to
resolve differences of opinion. On the other hand, if all we ever did
was to quote bits of the spec at each other without ever admitting any
personal interpretation of what it is actually supposed to mean, then
we really would be wasting out time.
From: Thomas F. Burdick
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <xcvwv08dkfk.fsf@conquest.OCF.Berkeley.EDU>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > > > Yes.  Read the section on evaluation and compilation in CLHS.
> > > 
> > > I have just perused it. I don't feel enlightened. I think CLHS is
> > > great as a reference, but I have great difficulty in using it to learn
> > > any concepts. I think you have to have a fair idea of what it is that
> > > you are looking up, to be able to profit from it. In this particular
> > > case I am just far too lost.
> > 
> > I didn't suggest you peruse it.  I suggested you read the entire chapter
> > linearly and in detail.
> 
> That is exactly how I started and continued for about half an hour. Not
> having learned anything that seemed to be directly relevant after this
> time, I looked through the rest much more quickly, coming to the
> conclusion that if I were to finish reading and inwardly digesting the
> section before trying to get input by other means, then I would not
> get to resolve my misunderstanding for man-months yet. The proportion
> of my time I can afford to spend on lisp makes this an un-viable
> option. As one who considers his time to be his most valuable
> commodity, I hope you will find some sympathy for my position.
> 
> That does not mean to say that I have given up on it. I fully intend
> to return to it, again and again, it's just that, well, (a) life goes
> on (b) other input might help me make better progress.

The nice thing about learning things from the hyperspec is that you
learn the whole thing.  The disadvantage is that you usually have to
learn the whole thing.  "ANSI Common Lisp" by Paul Graham, and "Lisp,
3d edition" by Winston are both good books that are introductions to
ANSI CL, as defined by the standared.  However, since you've already
laid out good money for "On Lisp", I'd suggest you try just working
through it some more.  The problem you were having with macros makes
me suspect that you haven't gotten very far into the book, or if you
have, you maybe should've been doing the exercises as you went along.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0ofljdqev.fsf@scumbag.ecs.soton.ac.uk>
···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> The nice thing about learning things from the hyperspec is that you
> learn the whole thing.  The disadvantage is that you usually have to
> learn the whole thing.

:-)

Very well put.
From: Pierre R. Mai
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <87lmgpe4o1.fsf@orion.bln.pmsf.de>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> On Lisp, p 101: "A macro call which occurs in a function definition
> gets replaced by its expansion when the function is compiled".

When you are seeking definitive knowledge of what is supposed to
happen, there is no substitute to looking at the ANSI Common Lisp
standard.

> Firstly, (though I guess that this is not all that important (not
> specified by the standard?)) what happens when only the interpreter is
> being used? It seems that implementations do not agree:

As you note, the standard doesn't specify how often macro-functions
are called, or when exactly.  Furthermore the standard doesn't require
the presence of either a compiler or an interpreter.  Implementations
are free to e.g. use a compiler as their "interpreter", or vice-versa.

CMU CL uses the first stage of its compiler to transform source to its
internal representation IR1, which it then interprets (except for very
simple forms).

> Secondly, what happens if the expansion is not invariant? 
> 
> (defun the-function (n)
>   (do-complicated-stuff)
>   (the-macro n)
>   (more-complicated-stuff))
> 
> (defmacro the-macro (n)
>   (some-expression-which-changes-as-a-function-of n))

The expansion is invariant.  n will always be bound to the symbol n.
The arguments to the macro function are always the unevaluated forms,
not their run-time values, because macro-expansion happens before
run-time (even in the interpreter, although that is allowed to lazily
interleave the two), and the value of n is only determinable at
run-time.

The expansion of the following macro isn't invariant:

(eval-when (:compile-toplevel :execute)
  (defvar *counter* 0))

(defmacro randomizer ()
  (incf *counter*))

(defun my-function ()
  (randomizer))

Since the standard doesn't specify how often and when this macro form
will be expanded, the value return by my-function can be anything.

The Lesson to take home:  Don't write macro-functions which depend on
the exact time or count of macro-expansion.

Regs, Pierre.

-- 
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
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0lmgp3xzb.fsf@scumbag.ecs.soton.ac.uk>
Pierre R. Mai <····@acm.org> writes:

> Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> > Secondly, what happens if the expansion is not invariant? 
> > 
> > (defun the-function (n)
> >   (do-complicated-stuff)
> >   (the-macro n)
> >   (more-complicated-stuff))
> > 
> > (defmacro the-macro (n)
> >   (some-expression-which-changes-as-a-function-of n))
> 
> The expansion is invariant.  n will always be bound to the symbol n.
> The arguments to the macro function are always the unevaluated
> forms, not their run-time values, because macro-expansion happens
> before run-time (even in the interpreter, although that is allowed
> to lazily interleave the two), and the value of n is only
> determinable at run-time.

Hmmmmm . . .

   * (defmacro the-macro (n)
       (hmm n))
   THE-MACRO
   * (defun hmm (n)
       (cons '* (loop for i from 1 to n collect i)))
   HMM
   * (the-macro 1)
   1
   * (the-macro 10)
   3628800
   * (defun the-function (n)
       (the-macro n))
   THE-FUNCTION
   * (the-function 1)
     (THE-MACRO N)
   Error: (during macroexpansion)

Yup. OK, that helps a lot, actually. Thanks.
From: Kent M Pitman
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <sfwvgftf2y1.fsf@shell01.TheWorld.com>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> Pierre R. Mai <····@acm.org> writes:
> 
> > Jacek Generowicz <···@ecs.soton.ac.uk> writes:
> 
> > > Secondly, what happens if the expansion is not invariant? 
> > > 
> > > (defun the-function (n)
> > >   (do-complicated-stuff)
> > >   (the-macro n)
> > >   (more-complicated-stuff))
> > > 
> > > (defmacro the-macro (n)
> > >   (some-expression-which-changes-as-a-function-of n))
> > 
> > The expansion is invariant.  n will always be bound to the symbol n.
> > The arguments to the macro function are always the unevaluated
> > forms, not their run-time values, because macro-expansion happens
> > before run-time (even in the interpreter, although that is allowed
> > to lazily interleave the two), and the value of n is only
> > determinable at run-time.
> 
> Hmmmmm . . .
> 
>    * (defmacro the-macro (n)
>        (hmm n))
>    THE-MACRO
>    * (defun hmm (n)
>        (cons '* (loop for i from 1 to n collect i)))
>    HMM
>    * (the-macro 1)
>    1
>    * (the-macro 10)
>    3628800
>    * (defun the-function (n)
>        (the-macro n))
>    THE-FUNCTION
>    * (the-function 1)
>      (THE-MACRO N)
>    Error: (during macroexpansion)
> 
> Yup. OK, that helps a lot, actually. Thanks.

It will also help you a lot to do:

 (pprint (macroexpand-1 '(the-macro 1)))

That will tell you what code is going to get compiled.
It will also help you understand which part of the computation
(the part that yields this result) gets done at macroexpand time.

You probably want
 (defun hmm (n)
   `(let ((result 1) (n ,n))
      (dotimes (i n)
        (setf result (* i result)))
      result))
Then try 
 (pprint (macroexpand-1 '(the-macro 10)))
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0snawv61k.fsf@scumbag.ecs.soton.ac.uk>
Kent M Pitman <······@world.std.com> writes:

> It will also help you a lot to do:
> 
>  (pprint (macroexpand-1 '(the-macro 1)))
> 
> That will tell you what code is going to get compiled.
> It will also help you understand which part of the computation
> (the part that yields this result) gets done at macroexpand time.

I have been doing it, and it only gave me false confidence, because I
got exactly what I was expecting . . . but I was asking the wrong
question.

What I should have been trying is (macroexpand-1 '(the-macro n))).

Lesson learned.

> You probably want
>  (defun hmm (n)
>    `(let ((result 1) (n ,n))
>       (dotimes (i n)
>         (setf result (* i result)))
>       result))

I see your point, but I don't immediately see that it can be appiled
to what I am really doing. (I trust that you don't think that I am
really trying to calculate factorials using macros.) I'll give it some
more thought.
From: Pierre R. Mai
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <87bshlvxri.fsf@orion.bln.pmsf.de>
Jacek Generowicz <···@ecs.soton.ac.uk> writes:

> Hmmmmm . . .
> 
>    * (defmacro the-macro (n)
>        (hmm n))
>    THE-MACRO
>    * (defun hmm (n)
>        (cons '* (loop for i from 1 to n collect i)))
>    HMM

You probably want list* here (identical result, but better
communicates your intent, IMHO), or some use of backquote.

>    * (the-macro 1)
>    1
>    * (the-macro 10)
>    3628800
>    * (defun the-function (n)
>        (the-macro n))
>    THE-FUNCTION
>    * (the-function 1)
>      (THE-MACRO N)
>    Error: (during macroexpansion)

That is because this will end up calling hmm with the symbol n, i.e. 

(hmm 'n)

which of course won't work...

Regs, Pierre.

-- 
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
From: Jacek Generowicz
Subject: Re: Macro expansion, times.
Date: 
Message-ID: <g0pu60v5w8.fsf@scumbag.ecs.soton.ac.uk>
"Pierre R. Mai" <····@acm.org> writes:

> >    * (defun hmm (n)
> >        (cons '* (loop for i from 1 to n collect i)))
> >    HMM
> 
> You probably want list* here (identical result, but better
> communicates your intent, IMHO),

Thanks, you learn a new operator every day.

> >    * (the-macro 1)
> >    1
> >    * (the-macro 10)
> >    3628800
> >    * (defun the-function (n)
> >        (the-macro n))
> >    THE-FUNCTION
> >    * (the-function 1)
> >      (THE-MACRO N)
> >    Error: (during macroexpansion)
> 
> That is because this will end up calling hmm with the symbol n, i.e. 
> 
> (hmm 'n)
> 
> which of course won't work...

Yes, I appreciate that now. Thanks.