Here's another generally useful macro which exists several places out
there. I hope we can agree on a specification so it can be added to
Common Lisp Utilities (<URL:http://ww.telent.net/cliki/
Common%20Lisp%20Utilities>).
- Vebjorn
Macro REBINDING
Syntax:
REBINDING ( { var | (var prefix) }* ) form* => result
Arguments and Values:
var---a symbol; not evaluated.
prefix---a string designator; not evaluated. The default is var.
form---a form.
results---the values returned by the forms.
Description:
Evaluates a series of forms in the lexical environment that is
formed by adding the binding of each var to a fresh, uninterned
symbol, and the binding of that fresh, uninterned symbol to var's
original value, i.e., its value in the current lexical
environment.
The uninterned symbol is created as if by a call to GENSYM with
the string denoted by prefix---or, if prefix is not supplied, the
string denoted by var---as argument.
The forms are evaluated in order, and the values of all but the
last are discarded (that is, the body is an implicit progn).
Examples:
To avoid multiple evaluation, macros are often written in the
following fashion:
(defmacro foo (var1 var2)
(let ((v1 (gensym))
(v2 (gensym)))
`(let ((,v1 ,var1)
(,v2 ,var2))
(+ (* ,v1 ,v1) (* ,v2 ,v2)))))
With REBINDING, the same can be achieved with
(defmacro foo (var1 var2)
(rebinding ((var1 :var1-)
(var2 :var2-))
`(+ (* ,var1 ,var1) (* ,var2 ,var2))))
The form (foo bar baz) then macroexpands to
(let ((#:var1-1019 bar)
(#:var2-1020 baz))
(+ (/ #:var1-1019 #:var1-1019) (* #:var2-1020 #:var2-1020)))
Side Effects:
Might increase *GENSYM-COUNTER* once for each var.
Affected By:
*GENSYM-COUNTER*
Exceptional Situations:
None.
See Also:
WITH-UNIQUE-NAMES, GENSYM, LET, LAMBDA
Status:
First draft posted to comp.lang.lisp for discussion. Suggested
for eventual inclusion in the layered community standard known as
Common Lisp Utilities.
Reference Implementation:
(defmacro rebinding (bindings &body body)
(loop
for binding in bindings
for var = (if (consp binding) (car binding) binding)
for name = (gensym)
collect `(,name ,var) into renames
collect ``(,,var ,,name) into temps
finally (return `(let ,renames
(with-unique-names ,bindings
`(let (,,@temps)
,,@body))))))
--
Vebjorn Ljosa
Vebjorn Ljosa <·····@ljosa.com> writes:
> results---the values returned by the forms.
If this were true, (let (x) (rebinding (x) t)) would evaluate to T.
Now it evaluates to (let ((#:x923 nil)) t).
> Evaluates a series of forms in the lexical environment that is
> formed by adding the binding of each var to a fresh, uninterned
> symbol, and the binding of that fresh, uninterned symbol to var's
> original value, i.e., its value in the current lexical
> environment.
The second set of bindings does not take effect when the
REBINDING form is evaluated. Rather, REBINDING puts a LET form
(or implementation-defined equivalent?) around the result (which
can be only one value) so that the bindings take effect when/if
the result is evaluated. Also, the LET form will evaluate the
original value of each var, instead of using them directly.