From: George Paschos
Subject: macro parameter passing (1)
Date: 
Message-ID: <1991Oct24.232130.4259@ecst.csuchico.edu>
Since there has been a number of responses to my first posting regarding
a problem with macros and the way parameters are passed, I think I should
give a clearer view of the problem I was facing.
(First of all,thanks to all the individuals who responded.) 

So, I was implementing the for macro e.g.

(for x from 1 to 11 as y in '(a b c) do (<s-expressions>))

and the way I did it was to map it to the 'do' command.
So, the macro is defined (with some abbreviations) as follows:

(defmacro for (&rest l)
 (setf no-as (before-do l) 
       body (after-do l)) ;;'no-as' set to ((x from 1 to 11)(y in '(a b c)))
			  ;;body is left intact
 (when (check no-as) (setup no-as body)))

where check()  checks for reserved words (e.g. to, in,...)and setup() produces
the code for the 'do' command. 

In the first place, I was trying to do type checking for the arguments
(e.g. upper/lower bounds to be integers etc).That works when you call the
macro as above shown but you couldn't call it with variable arguments
(e.g. (for x from m to n do (...)) where m,n have been previously assigned 
values).The type checking fails terribly.
So, I just abandoned the idea of type checking and contended myself to
just checking for the syntactic markers.

So, as a last word, it seems to me that you can call a macro both with variables
and with actual values.
Any further comments are wellcome, especially if I seem to miss something again.

regards,

George.

P.S. After all,maybe my question had a premature birthdate.
From: Bob Kerns
Subject: Re: macro parameter passing (1)
Date: 
Message-ID: <1991Oct25.051417.16750@crl.dec.com>
In article <·····················@ecst.csuchico.edu>, ········@ecst.csuchico.edu (George Paschos) writes:
> Since there has been a number of responses to my first posting regarding
> a problem with macros and the way parameters are passed, I think I should
> give a clearer view of the problem I was facing.
> (First of all,thanks to all the individuals who responded.) 
> 
> So, I was implementing the for macro e.g.
> 
> (for x from 1 to 11 as y in '(a b c) do (<s-expressions>))

Well, the easy way to define this is as follows:

(defmacro for (&rest specs)
  `(loop for ,@specs))

But people would probably find your code more readable if
you just used LOOP instead of FOR, and you'll save yourself
some work, besides.  The current versions of all the Lisps
I know about come with the either the ANSI version of LOOP
which has these features, or a close predecessor which will
be close enough that you should have no problem using it.

But anyway, to answer your question:

> and the way I did it was to map it to the 'do' command.
> So, the macro is defined (with some abbreviations) as follows:
> 
> (defmacro for (&rest l)
>  (setf no-as (before-do l) 
>        body (after-do l)) ;;'no-as' set to ((x from 1 to 11)(y in '(a b c)))
> 			  ;;body is left intact
>  (when (check no-as) (setup no-as body)))

Well, this is pretty much right, and not where your problem is.
One minor suggestion, and one larger one.

The minor one:  I hope that CHECK calls WARN to tell the user
about the problem.

The major one:  You should be using LET to bind NO-AS and BODY
locally, not setting the global values.  I.e.

(defmacro for (&rest l)
  (let ((no-as (before-do l)))
        (body (after-do l)))
    (when (check no-as)
      (setup no-as body))))

> where check()  checks for reserved words (e.g. to, in,...)and setup() produces
> the code for the 'do' command. 

Well, what gets evaluated and what doesn't depends
entirely on what SETUP returns.

For

(FOR X FROM LOW TO HIGH AS Y IN LIST DO (PRINT (LIST X Y)))

SETUP should return something like:

(DO* ((X LOW)
      (#:LIMIT-01 HIGH)
      (#:LIST-02 LIST)
      (Y)
     (())
  (WHEN (> (INCF X) #:LIMIT-01)
     (RETURN NIL))
  (IF #:LIST-02
      (SETQ Y (POP #:LIST-02))
     (RETURN NIL))
  (PRINT (LIST X Y)))

Thus SETUP causes LOW, HIGH, LIST, and (PRINT (LIST X Y)))
to be evaluated by placing them in places in the code where
they will be evaluated when the code runs.

SETUP causes X and Y to be bound locally and get values
by placing them in places in the code so it binds them,
and gives them values.  Note that they're given values,
not evaluated, because they're placed in places which
give them values, not evaluate them.

SETUP causes the syntactic markers FROM TO AS IN and DO
to not be evaluated, by not including them in the code
at all.

Sometimes macro arguments are included in the
code in places which are not evaluated, such as within
a QUOTE:

to get:
(DEFALIAS FRED JIM)

write:
(DEFMACRO DEFALIAS (NAME ALIAS)
  `(SETF (GETHASH ',NAME *ALIASES*) ',JIM))

Which expands as:

(SETF (GETHASH 'FRED *ALIASES*) 'JIM)

> In the first place, I was trying to do type checking for the arguments
> (e.g. upper/lower bounds to be integers etc).That works when you call the
> macro as above shown but you couldn't call it with variable arguments
> (e.g. (for x from m to n do (...)) where m,n have been previously assigned 
> values).The type checking fails terribly.
> So, I just abandoned the idea of type checking and contended myself to
> just checking for the syntactic markers.

Macros are about converting between one syntax and another.
So indeed, they are only responsible for checking the syntactic
markers.

You have to understand the difference between when macros run and
when your code runs.  Macros run when you compile your file, and
produce code which is then run later.  If M and N haven't been
previously assigned values; they'll be assigned values LATER when
you finally run your code!

If you have just been learning macros by typing them at the
interpreter and running them, it is very easy to miss this
distinction, and start thinking of macros evaluating their
arguments.

When you write your macros, think about them running before
any of the code which uses them, and write them accordingly.

Macros can only operate on the data that is there in the
call, or on other data which has been saved earlier
in the compilation.  For example, one macro may store away
some data for another macro to use, or you might build a
table inside an (EVAL-WHEN (EVAL COMPILE LOAD) ...).

If you pass a variable or form to a macro, the macro will
never see the variable or form's value.  Anything which
depends on the value must be done by the code that the
macro turns into, and not by the macro.

SETUP could supply a call to CHECK-TYPE or ASSERT, like this:

(DO* ((#:LOWER-LIMIT-0 LOW)
      (#:LIMIT-1 HIGH)
      (X (PROGN (CHECK-TYPE #:LOWER-LIMIT-0 REAL)
                (CHECK-TYPE #:LIMIT-1 REAL)
                (ASSERT (>= #:LIMIT-1 #:LOWER-LIMIT-0))
                LOW))
      (#:LIST-02 LIST)
      (Y)
     (())
  (WHEN (> (INCF X) #:LIMIT-01)
     (RETURN NIL))
  (IF #:LIST-02
      (SETQ Y (POP #:LIST-02))
     (RETURN NIL))
  (PRINT (LIST X Y)))

(Although I would claim that it is legitimate for the lower
limit to be higher; the loop will just terminate immediately.)

As a special case, when you supply a number directly (that is,
the form you supply is a number to evaluate to itself), the
macro can look at it and do the checking at macro expansion
time.