From: Scott Alexander
Subject: Using 'dolist' in a macro definition form
Date: 
Message-ID: <CMKtJI.62L@world.std.com>
I have been reading and re-reading the definition of the backquote 
mechanism on pages 527-529 of CLtL but I am still struggling to
get it to accomplish what would seem to be a fairly straightforward 
task:  I want to be able to pass a list of symbols to the macro 
and then use each symbol as the name of, say, a new function 
(or class) in a call to 'defun' (or 'defclass') in the macro expansion. 

When I define a macro whose lambda-expression consists of a single
element - a list of symbols - I have trouble using 'dolist' to 
iterate through these symbols in the macro body and use each one as
the function name in repeated calls to 'defun'.  

To illustrate with a contrived example, suppose I want to define
a macro 'defsums' which, when passed a list of symbols, makes each
of those symbols into a binary addition function, by using 'defun' 
and Lisp's built-in '+' function.  In other words, we want evaluation of
the top-level form

   (defsums (add-up total sigma))

to macro-expand into the following three top-level forms:

   (defun addup (x y) (+ x y))
   (defun total (x y) (+ x y))
   (defun sigma (x y) (+ x y))

defining functions 'addup', 'total' and 'sigma' so that forms like

   (add-up 2 3)

or

   (total 2 3)

would subsequently evaluate to '5'.

The naive approaches shown below, using 'dolist' to iterate over the 
list of symbols and pass each one in turn to 'defun', evaluate 
without warnings but don't yield the correct macro 'defsums':

   (defmacro defsums (symbol-list)  ; *** WRONG ***
     `(dolist (s ,symbol-list)
       (defun s (x y) (+ x y))))

   (defmacro defsums (symbol-list)   ; *** WRONG ***
       (dolist (s symbol-list)
         `(defun ,s (x y) (+ x y))))

I realize the same name may simultaneously stand for a variable 
and a function in Lisp, so maybe the 's' after the 'defun' 
in the above call to 'dolist' refers to the loop iteration variable
's' and not to the symbol I am trying to bind to a function definition.  
An alternate approach, using 'dotimes' to avoid applying 'defun' 
directly to the loop iteration variable, also fails to work:

   (defmacro defsums (symbol-list)   ; *** STILL WRONG ***
       (dotimes (i (length symbol-list))
         `(defun ,(nth i symbol-list) (x y) (+ x y))))

However, I am able to define a similar, less useful macro 
'def2sums' which passes the symbol at the 'car' and then the 
symbol at the 'cadr' of its argument list to two, "hard-coded" 
calls to 'defun': 

   (defmacro def2sums (symbol-list)  ; *** WORKS, CLUMSILY ***
       `(defun ,(car symbol-list) (x y) (+ x y))
       `(defun ,(cadr symbol-list) (x y) (+ x y)))

so that after the macro call: 

   (def2sums (add-up total sigma))

two new functions 'add-up' and 'total' are defined, and the forms

  (add-up 2 3)

and 

  (total 2 3)

both evaluate to '5'... but the form 

  (sigma 2 3)

signals an error, "undefined function SIGMA".

Of course, the idea is to do this for 'symbol-list' of any length,
which seems to require embedding the backquoted call to 'defun'
within a call to 'dolist' or maybe 'dotimes' - which I can't figure
out how to do properly!

Any advice would be greatly appreciated.  Thanks!

Scott Alexander

········@world.std.com

The San Juan Star (newspaper)
San Juan, Puerto Rico

From: ·····@pharlap.ci.com
Subject: Re: Using 'dolist' in a macro definition form
Date: 
Message-ID: <9403131540.AA03002@pharlap.ci.com>
Remember that a macro's purpose is to generate CODE, not to do actual work. 

So the trick is to have your macro cons up defuns and then return them
wrapped in a progn, so it's effectively a single form.

(defmacro dosyms (symbol-list)
  (let ((defuns nil))
    (dolist (s symbol-list)
      (push `(defun ,s (x y) (+ x y)) defuns))
    `(progn ,@defuns))

You can reverse the defuns list if you need to `(progn ,@(nreverse defuns)).

> (macroexpand-1 '(dosyms (a b c d)))
(PROGN (DEFUN D (X Y) (+ X Y))
       (DEFUN C (X Y) (+ X Y))
       (DEFUN B (X Y) (+ X Y))
       (DEFUN A (X Y) (+ X Y)))

Notice you can also define the dosyms macro to take an &rest argument so you don't
need to send them in inside a list.

(defmacro dosyms (&rest symbol-list) ...)

(dosyms a b c d)

--
David Kuznick - ·····@ci.com (preferred) or ········@world.std.com
"Skylight's now open to you friend, like a swallow you can swoop and dive.
 But I'm never gonna lose your precious heart,
 Now you can see through the window of life." The Last Man on Earth: PENDRAGON
:-)
From: Michael Callahan
Subject: Re: Using 'dolist' in a macro definition form
Date: 
Message-ID: <1994Mar13.111533.12932@hellgate.utah.edu>
Macros work by doing code substitution, not by actually doing an eval.
Think about what you want to turn a form into.

something like:

(make-sums (a b c)) -->

(progn
  (defun a (x y) (+ x y))
  (defun b (x y) (+ x y))
  (defun c (x y) (+ x y)))


Then writing the macro is the easy part.  I didn't want to use dolist,
since you have to cons up a list.  I used mapcar instead.

(defmacro make-sum (list)
  (cons 'progn (mapcar #'(lambda (ele) `(defun ,ele (x y) (+ x y))) list)))


(macroexpand '(make-sum (a b c))) -->

(PROGN (DEFUN A (X Y) (+ X Y)) (DEFUN B (X Y) (+ X Y)) (DEFUN C (X Y) (+ X Y)))


  mike