[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Using Macros in Lisp
- To: Gallagher@gilgamesh.cs.umass.edu
- Subject: Using Macros in Lisp
- From: Andrew L. M. Shalit <alms>
- Date: Fri, 8 Mar 91 13:10:53 -0500
- Cc: keunen@milou.nrb.BE, info-macl
- In-reply-to: Kevin Gallagher's message of Fri, 8 Mar 91 12:10:10 EST <2877441010-12466397@Gilgamesh>
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))))