From: Vebjorn Ljosa
Subject: REBINDING specification
Date: 
Message-ID: <cy3wv0fya0p.fsf@ljosa.com>
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
From: Kalle Olavi Niemitalo
Subject: Re: REBINDING specification
Date: 
Message-ID: <87adxbxlru.fsf@Astalo.y2000.kon.iki.fi>
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.