[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Using Macros in Lisp
- To: alms@cambridge.apple.com
- Subject: Using Macros in Lisp
- From: Eric Benson <eb@lucid.com>
- Date: Fri, 8 Mar 91 11:44:39 PST
- Cc: Gallagher@gilgamesh.cs.umass.edu, keunen@milou.nrb.BE, info-macl@cambridge.apple.com
- In-reply-to: Andrew L. M. Shalit's message of Fri, 8 Mar 91 13:10:53 -0500 <9103081810.AA24543@cambridge.apple.com>
Date: Fri, 8 Mar 91 13:10:53 -0500
From: Andrew L. M. Shalit <alms@cambridge.apple.com>
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))))
All of which is why it is far better to write
(proclaim '(inline double))
(defun double (number)
(+ number number))