From: ·············@levels.sait.edu.au
Subject: macro misbehaviour
Date: 
Message-ID: <16456.285261a2@levels.sait.edu.au>
Please help..... I use VAX Lisp, and have come across some annoying behaviour.
I would like to know:
1. why it occurs;        (I suspect that it is some kind of optimization)
2. how to get around it.

The Problem:
Given the following macros and function:

    (DEFMACRO TRY (X) (LET ((A (EVAL X))) `(TT ,(MAPCAR #'ADD-1 A))))

    (DEFUN ADD-1 (X) (1+ X))

    (DEFMACRO TT (X) `(FORMAT T "~a ~%" ',X))

and the following code:

   (dotimes (n 3)
     (let ((a (list n n n)))
       (try a)))

I get the following results:

   (1 1 1)
   (1 1 1)
   (1 1 1)

when I would expect:

   (1 1 1)
   (2 2 2)
   (3 3 3)

It appears that the first call is evaluated, but further calls are 'recognised'
as being the same as previous calls (despite the fact that the value of
n and therefore a has changed), bypasses evaluation of the mapcar form, and
sends the previous result to macro tt.

Has anyone and explanation? and HOW CAN I GET AROUND IT???


Regards, and thanks in advance,
Jenny Rowland

--------

·············@sait.edu.au
University of South Australia

.....You play, you win, you play, you lose, you play...
                                                      J Winterson

From: Barry Margolin
Subject: Re: macro misbehaviour
Date: 
Message-ID: <1991Jun9.141232.25632@Think.COM>
In article <··············@levels.sait.edu.au> ·············@levels.sait.edu.au writes:
>    (DEFMACRO TRY (X) (LET ((A (EVAL X))) `(TT ,(MAPCAR #'ADD-1 A))))
>    (DEFUN ADD-1 (X) (1+ X))
>    (DEFMACRO TT (X) `(FORMAT T "~a ~%" ',X))
>   (dotimes (n 3)
>     (let ((a (list n n n)))
>       (try a)))
>
>I get the following results:
>
>   (1 1 1)
>   (1 1 1)
>   (1 1 1)
>
>when I would expect:
>
>   (1 1 1)
>   (2 2 2)
>   (3 3 3)

The problem is your use of EVAL.  I'm surprised you didn't get an unbound
variable error regarding A; I suspect you had previously done

	(setq a '(0 0 0))

Unless you proclaim A special, LET binds it as a lexical variable.  EVAL
operates in the null lexical environment, so it isn't affected by this
binding.

However, even if you were to proclaim it special you might see this kind of
behavior.  Compilers must, and some interpreters do, expand macros before
executing any of the code.  Thus, the macro would be evaluated prior to
binding the variable in the LET.

This is why it is almost always wrong to use EVAL in macros.
-- 
Barry Margolin, Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar
From: SRINIVASAN,K
Subject: Re: macro misbehaviour
Date: 
Message-ID: <30996@hydra.gatech.EDU>
I have a similar problem too.  

I wrote the follwing macro for reading a file and defining classes.
During any single iteration, the three calls to "read" read three
succesive symbols from the file as you would expect.  However, during
successive iterations, the same set of three symbols are read repeatedly.
So, I get the same class defined 4 times instead of defining 4 different
classes.  If I put in 4 explicit calls contained in a progn form instead
of the do-loop, it works fine.  Can somebody please help me fix this 
problem.  Thanks in advance.

Define-Class is a macro calling defclass (written by Marty Hall of AAI Corp.,
and very kindly shared with me). 


(defmacro class-from-file (file-name)
  (with-open-file (input-stream file-name
				:direction :input)
    `(do ((q 4 (- q 1))) ((= q 0) nil)
      (Define-Class ,(read input-stream) ,(read input-stream) .,(read input-stream)))))


-- 
SRINIVASAN,K
School of Textile Engineering   Georgia Tech.
uucp: ...!{allegra,amd,hplabs,seismo,ut-ngp}!gatech!prism!gt4084c
ARPA: ·······@prism.gatech.edu
From: Bruce Krulwich
Subject: Re: macro misbehaviour
Date: 
Message-ID: <2034@anaxagoras.ils.nwu.edu>
Two recently posted macro questions suffer from the same problem:

In article <··············@levels.sait.edu.au>, ·············@levels writes:
>    (DEFMACRO TRY (X) (LET ((A (EVAL X))) `(TT ,(MAPCAR #'ADD-1 A))))
>    (DEFUN ADD-1 (X) (1+ X))
>    (DEFMACRO TT (X) `(FORMAT T "~a ~%" ',X))
>and the following code:
>   (dotimes (n 3)
>     (let ((a (list n n n)))
>       (try a)))
>I get the following results:
>   (1 1 1)
>   (1 1 1)
>   (1 1 1)
>It appears that the first call is evaluated, but further calls are
>'recognised' as being the same as previous calls (despite the fact that the
>value of n and therefore a has changed), bypasses evaluation of the mapcar
>form, and sends the previous result to macro tt.


In article <·····@hydra.gatech.EDU>, ·······@prism (SRINIVASAN,K) writes:
>During any single iteration, the three calls to "read" read three
>succesive symbols from the file as you would expect.  However, during
>successive iterations, the same set of three symbols are read repeatedly.
>So, I get the same class defined 4 times instead of defining 4 different
>classes.
>
>(defmacro class-from-file (file-name)
> (with-open-file (input-stream file-name
>                       :direction :input)
>   `(do ((q 4 (- q 1))) ((= q 0) nil)
>     (Define-Class ,(read input-stream) ,(read input-stream) 
>                   .,(read input-stream)))))

In each case there is some code that is only run once that "should" be run
several times.

The problem in each case is that computation is done at the time the macro is
expanded that should be done at the time the macro result is executed.  In
other words, the code for a DEFMACRO (i.e., the code which takes arguments and
returns a list which is later executed) can and should only be executed once,
and the list which it returns is then plugged into the program and executed as
often as desired.

In the above macros, the code which is only executed once (the MAPCAR in the
first example, and the WITH-OPEN-FILE / READ in the second) is executed at the
time the code is compiled (or parsed by the interpreter), and the result (the
result of MAPCARing at compile-time, or the thing read from the file at
compile-time) is plugged into the loops.

Hope this helps.

Bruce Krulwich
········@ils.nwu.edu