From: Lee Christensen
Subject: Question about macros
Date: 
Message-ID: <6616c19a.0305060947.f6a7125@posting.google.com>
Greetings:

I have a question:

I would like to write a macro, 'with-alist-binds, to convert a list of
dotted pairs into bound local variables.  For instance, it would
expand this:

(let ((lst '((x . 1) (y . 2))))
  (with-alist-binds (lst) (+ x y)))

into this:

(let ((x 1) (y 2))
  (+ x y))

My first thought would be something like this:

(defmacro with-alist-binds ((binds) &rest body)
  (loop for pair in binds 
      collect `(,(car pair) ,(cdr pair)) into bindings
        finally
        (return
          `(let ,bindings ,@body))))

Of course, I understand that macroexpansion takes place before the
local variable 'lst is allocated and assigned, and this will produce
an error.  But is there a right way to do this sort of thing?

Many thanks in advance,

Lee Christensen
IHC Corporation

From: Barry Margolin
Subject: Re: Question about macros
Date: 
Message-ID: <%fTta.23$_74.1691@paloalto-snr1.gtei.net>
In article <···························@posting.google.com>,
Lee Christensen <········@ihc.com> wrote:
>Greetings:
>
>I have a question:
>
>I would like to write a macro, 'with-alist-binds, to convert a list of
>dotted pairs into bound local variables.  For instance, it would
>expand this:
>
>(let ((lst '((x . 1) (y . 2))))
>  (with-alist-binds (lst) (+ x y)))
>
>into this:
>
>(let ((x 1) (y 2))
>  (+ x y))
>
>My first thought would be something like this:
>
>(defmacro with-alist-binds ((binds) &rest body)
>  (loop for pair in binds 
>      collect `(,(car pair) ,(cdr pair)) into bindings
>        finally
>        (return
>          `(let ,bindings ,@body))))
>
>Of course, I understand that macroexpansion takes place before the
>local variable 'lst is allocated and assigned, and this will produce
>an error.  But is there a right way to do this sort of thing?

You can do it by expanding into something that uses EVAL:

(defmacro with-alist-binds ((binds) &rest body)
  `(eval `(let ,(loop for (var . val) in ,binds collect (list var val))
               ,,@body)))

I haven't tested this, so I might not have some of the nested backquote
right.

But without EVAL, there's no way to create lexical bindings of variables
that aren't known until run time.  You could use PROGV, but it creates
dynamic bindings, so it will only work if the variables are special.

Why do you think you need to do this?  What's the higher-level goal?

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, a Level(3) Company, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Alexey Dejneka
Subject: Re: Question about macros
Date: 
Message-ID: <m3ade0ey9q.fsf@comail.ru>
········@ihc.com (Lee Christensen) writes:

> I would like to write a macro, 'with-alist-binds, to convert a list of
> dotted pairs into bound local variables.  For instance, it would
> expand this:
> 
> (let ((lst '((x . 1) (y . 2))))
>   (with-alist-binds (lst) (+ x y)))
> 
> into this:
> 
> (let ((x 1) (y 2))
>   (+ x y))
> 
> My first thought would be something like this:
> 
> (defmacro with-alist-binds ((binds) &rest body)
>   (loop for pair in binds 
>       collect `(,(car pair) ,(cdr pair)) into bindings
>         finally
>         (return
>           `(let ,bindings ,@body))))
> 
> Of course, I understand that macroexpansion takes place before the
> local variable 'lst is allocated and assigned, and this will produce
> an error.  But is there a right way to do this sort of thing?

You can do it for special variables with PROGV:

* (defvar *x* :x-default)
*X*
* (defvar *y* :y-default)
*Y*
* (defun test (vars vals)
    (progv vars vals (list *x* *y*)))
TEST
* (test '() '())
(:X-DEFAULT :Y-DEFAULT)
* (test '(*x*) '(:x-new))
(:X-NEW :Y-DEFAULT)

So you only need to split an alist. But it does not work with
lexicals.

-- 
Regards,
Alexey Dejneka

"Alas, the spheres of truth are less transparent than those of
illusion." -- L.E.J. Brouwer
From: Coby Beck
Subject: Re: Question about macros
Date: 
Message-ID: <b99sg9$1org$1@otis.netspace.net.au>
"Lee Christensen" <········@ihc.com> wrote in message
································@posting.google.com...
> Greetings:
>
> I have a question:
>
> I would like to write a macro, 'with-alist-binds, to convert a list of
> dotted pairs into bound local variables.  For instance, it would
> expand this:
>
> (let ((lst '((x . 1) (y . 2))))
>   (with-alist-binds (lst) (+ x y)))
>
> into this:
>
> (let ((x 1) (y 2))
>   (+ x y))
>

Since your code must know that x and y are in there to be useful, why are
you calling with-alist-binds with a variable rather than the data directly?
If you can call it like this:

(with-alist-binds ((x . 1) (y . 2))
   (+ x y)))

Then you can write your macro like this:

CL-USER 6 >
(defmacro with-alist-binds (bindings &rest code)
  `(let (,@(mapcar #'(lambda (binding)
                       `(,(car binding) ,(cdr binding)))
                   bindings))
     ,@code))
WITH-ALIST-BINDS

CL-USER 7 >
(with-alist-binds ((x . 1) (y . 2))
    (+ x y))
3

Otherwise, you'll have to put an eval in there:

CL-USER 9 >
(defmacro with-alist-binds (bindings &rest code)
  `(let (,@(mapcar #'(lambda (binding)
                       `(,(car binding) ,(cdr binding)))
                   (eval bindings)))
     ,@code))
WITH-ALIST-BINDS

CL-USER 10 > (setf data '((x . 1) (y . 2)))
((X . 1) (Y . 2))

CL-USER 11 >
(with-alist-binds data
    (+ x y))
3

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")