[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Using Macros in Lisp

   Sender: Gallagher@Gilgamesh
   Date: Fri, 8 Mar 91  12:10:10 EST
   Reply-To: Gallagher@gilgamesh.cs.umass.edu
   From: Kevin Gallagher <Gallagher@gilgamesh.cs.umass.edu>

   The notion of double evaluation comes from a time when most lisp
   programs were interpreted, and the compiler was seen as a somewhat
   cumbersome and untrustworthy facility.  Because you would develop and
   debug your programs in the interpreter, you didn't see any difference
   between the semantics of macro expansion (the first evaluation) and
   executing the expanded form (the second evaluation).  This hid the fact
   that the semantics of the two evaluations were different until you
   (shudder) compiled your program.

This isn't what I consider the 'double evaluation' problem of macros.

Consider the macro DOUBLE

(defmacro double (number-form)
  `(+ ,number-form ,number-form))

This yields

(double 10)  ==>> (+ 10 10)

But it also yields

(double (incf foo))  ==>>  (+ (incf foo) (incf foo))

In the second example, the expression (incf foo) is placed in the
source code more than once, and so the side-effect of the expression
happens more than once.  This probably isn't what was intended by the
author of the macro or the user of the macro.

To get around this, Common Lisp macros should ensure that value forms
are evaluated once, and only once.

A first cut would yield

(defmacro double (number-form)
  `(let ((temp ,number-form))
     (+ temp temp)))

But, of course, this fails because the use of the variable TEMP isn't
hygenic.  So, to have the real version, we need to write:

(defmacro double (number-form)
  (let ((number-var (make-variable "NUMBER")))
    `(let ((,number-var ,number-form))
       (+ ,number-var ,number-var))))