From: Dr. Edmund Weitz
Subject: Macros that evaluate some of their arguments
Date: 
Message-ID: <m3n137u8lu.fsf@bird.agharta.de>
Hello!

I understand that what I'm asking for in the subject line is a special
form and that I can't create such a thing. But I still think there
must be better solution to my problem than the one that I came up
with. Here it is:

I've written a macro that basically looks like this:

(defmacro set-from-list (places-list value-list)
  `(progn
     ,@(mapcar #'(lambda (place value)
                   `(setf ,place ,value))
               places-list (eval value-list))))

The idea is that I'll be able to say things like

(set-from-list (x y) '(1 2))

resulting in 1 being assigned to x and 2 being assigned to y. What
bugs me is that I have to call eval while every book says I should
avoid it like the plague. Is there a better way to do this?

Thanks in advance,
Edi.

PS: I know that in the example above I can simply remove the call to
eval and call the macro like

(set-from-list (x y) (1 2))

but this of course won't work if the call is little bit more
complicated, like

(set-from-list (x y) (cons 1 '(2)))

From: Dr. Shlomo Argamon
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <tighetfdczg.fsf@sunlight.i-have-a-misconfigured-system-so-shoot-me>
···@agharta.de (Dr. Edmund Weitz) writes:

> 
> Hello!
> 
> I understand that what I'm asking for in the subject line is a special
> form and that I can't create such a thing. But I still think there
> must be better solution to my problem than the one that I came up
> with. Here it is:
> 
> I've written a macro that basically looks like this:
> 
> (defmacro set-from-list (places-list value-list)
>   `(progn
>      ,@(mapcar #'(lambda (place value)
>                    `(setf ,place ,value))
>                places-list (eval value-list))))
> 
> The idea is that I'll be able to say things like
> 
> (set-from-list (x y) '(1 2))
> 
> resulting in 1 being assigned to x and 2 being assigned to y. What
> bugs me is that I have to call eval while every book says I should
> avoid it like the plague. Is there a better way to do this?

Try the following:

(defmacro set-from-list (places-list value-list)
  (let ((var (gensym)))
    `(let ((,var ,value-list))
       (mapcar #'(lambda (place value)
                   (set place value))
                 (quote ,places-list) ,var))))
                                                 
This only works to set symbols, however.  You can't, with this, do:

(set-from-list ((car a) (cdr b)) '(1 2))

	-Shlomo-
From: Dr. Edmund Weitz
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <m3bsjnu7bc.fsf@bird.agharta.de>
·······@sunlightNOSPAM.cs.biu.ac.il (Dr. Shlomo Argamon ) writes:

> Try the following:
> 
> (defmacro set-from-list (places-list value-list)
>   (let ((var (gensym)))
>     `(let ((,var ,value-list))
>        (mapcar #'(lambda (place value)
>                    (set place value))
>                  (quote ,places-list) ,var))))
>                                                  
> This only works to set symbols, however.  You can't, with this, do:
> 
> (set-from-list ((car a) (cdr b)) '(1 2))

Thanks, that does the job in my case. However, in my original solution
I named the argument 'places-list' because I was aware of the fact
that I _could_ - if I wanted to - use generalized variables instead of
symbols. I'm still curious if there is a solution for the more general
approach that doesn't use eval.

Thanks again,
Edi.
From: Dr. Edmund Weitz
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <m3wv2bsqus.fsf@bird.agharta.de>
···@agharta.de (Dr. Edmund Weitz) writes:

> Thanks, that does the job in my case. However, in my original solution
> I named the argument 'places-list' because I was aware of the fact
> that I _could_ - if I wanted to - use generalized variables instead of
> symbols. I'm still curious if there is a solution for the more general
> approach that doesn't use eval.

Sorry for replying to my own post, but what if - as it turns out now -
I actually need let instead of setf. My solution would be something
like

(defmacro let-from-list ((var-list value-list) &body body)
  `(let ,(mapcar #'(lambda (var value)
                     (list var value))
                 var-list (eval value-list))
     ,@body))

which still has eval hanging around there...

Thanks,
Edi.
From: Christopher J. Vogt
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <3BBC6514.2D291981@computer.org>
"Dr. Edmund Weitz" wrote:
> 
> ···@agharta.de (Dr. Edmund Weitz) writes:
> 
> > Thanks, that does the job in my case. However, in my original solution
> > I named the argument 'places-list' because I was aware of the fact
> > that I _could_ - if I wanted to - use generalized variables instead of
> > symbols. I'm still curious if there is a solution for the more general
> > approach that doesn't use eval.
> 
> Sorry for replying to my own post, but what if - as it turns out now -
> I actually need let instead of setf. My solution would be something
> like
> 
> (defmacro let-from-list ((var-list value-list) &body body)
>   `(let ,(mapcar #'(lambda (var value)
>                      (list var value))
>                  var-list (eval value-list))
>      ,@body))

You might want to take a look at progv
From: Kalle Olavi Niemitalo
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <izng08za4hp.fsf@stekt34.oulu.fi>
"Christopher J. Vogt" <····@computer.org> writes:

> You might want to take a look at progv

Especially the second example in the CLHS.
From: Erik Haugan
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <87y9mrhaov.fsf@kometknut.neitileu.no>
* ·······@sunlightNOSPAM.cs.biu.ac.il (Dr. Shlomo Argamon )
> Try the following:
> 
> (defmacro set-from-list (places-list value-list)
>   (let ((var (gensym)))
>     `(let ((,var ,value-list))
>        (mapcar #'(lambda (place value)
>                    (set place value))
>                  (quote ,places-list) ,var))))
>                                                  
> This only works to set symbols, however.  You can't, with this, do:
> 
> (set-from-list ((car a) (cdr b)) '(1 2))

Not only that, you can't set lexical variables either.  You can only set
symbol values (which i guess is what you mean by "set symbols").

Erik
From: Kent M Pitman
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <sfwvghv71nl.fsf@world.std.com>
·······@sunlightNOSPAM.cs.biu.ac.il (Dr. Shlomo Argamon ) writes:

> Try the following:
> 
> (defmacro set-from-list (places-list value-list)
>   (let ((var (gensym)))
>     `(let ((,var ,value-list))
>        (mapcar #'(lambda (place value)
>                    (set place value))
>                  (quote ,places-list) ,var))))

NO.

Don't use SET either. :-)  Its use is a red flag unless you are a very
sophisticated user.  Ditto for SETF of SYMBOL-VALUE.  These should mostly be
done only at toplevel in bootstrap code that's trying to get a foothold
on a "hostile" package, or sometimes in error-correction code.  Most of the
time you are bypassing the normal lexical variable binding mechanism when
you use this in code and that's not usually right (unless you mean to be 
affecting only special variables, etc.)

> This only works to set symbols, however.  You can't, with this, do:
> 
> (set-from-list ((car a) (cdr b)) '(1 2))

That's what makes it the wrong thing.

Instead of using EVAL, always put the thing you have in the path of
the evaluator which is naturally on its way rolling through.  Something
like the following (no, I didn't test it) should work:

 (defmacro set-from-list (places-list value-list)
   (let ((temps (mapcar #'(lambda (place) 
                            (declare (ignore place))
                            (gensym))
                        places-list)))
     `(destructuring-bind ,temps ,value-list
        (setf ,@(mapcan #'list places-list temps)))))

Your problem in needing EVAL is that you quoted the places list and that
forced you to have to evaluate it.  If you don't quote it, you won't need
to be trying (unsuccessfully) to undo the damage (loss of lexical
environment) done by the spurious quotation.  Once you throw away the
lexical environment,  you can't get it back.
From: Kalle Olavi Niemitalo
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <87wv2bdxnh.fsf@Astalo.y2000.kon.iki.fi>
Kent M Pitman <······@world.std.com> writes:

>  (defmacro set-from-list (places-list value-list)
>    (let ((temps (mapcar #'(lambda (place) 
>                             (declare (ignore place))
>                             (gensym))
>                         places-list)))
>      `(destructuring-bind ,temps ,value-list
>         (setf ,@(mapcan #'list places-list temps)))))

That works indeed, and detects list-length mismatches in safe
code unlike my POP solution.

However, neither macro preserves the standard left-to-right
evaluation order.  How difficult would it be to evaluate the
subforms of PLACES-LIST elements before VALUE-LIST?

  (let ((x '()))
    (set-from-list ((cdr (push 42 x))) (copy-list x))
    ;; which means: (setf (cdr (push 42 x)) (first x))
    x)  ; should be (42 . 42)

I put the COPY-LIST call there so that the code expanded from the
macro can't be confused by the length of the source list changing
under it.

I would like to see a more realistic test case, too.
From: Barry Margolin
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <8b4v7.19$5h1.856@burlma1-snr2>
In article <··············@Astalo.y2000.kon.iki.fi>,
Kalle Olavi Niemitalo  <···@iki.fi> wrote:
>However, neither macro preserves the standard left-to-right
>evaluation order.  How difficult would it be to evaluate the
>subforms of PLACES-LIST elements before VALUE-LIST?
>
>  (let ((x '()))
>    (set-from-list ((cdr (push 42 x))) (copy-list x))
>    ;; which means: (setf (cdr (push 42 x)) (first x))
>    x)  ; should be (42 . 42)
>
>I put the COPY-LIST call there so that the code expanded from the
>macro can't be confused by the length of the source list changing
>under it.

It can be done, but it's not a simple macro like the ones that have been
posted so far.  You have to use GET-SETF-EXPANDER so that you can arrange
for the subforms of all the places to be evaluated and saved before
evaluating the value form and then performing the assignments.

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Kent M Pitman
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <sfwpu82ppvg.fsf@world.std.com>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> >  (defmacro set-from-list (places-list value-list)
> >    (let ((temps (mapcar #'(lambda (place) 
> >                             (declare (ignore place))
> >                             (gensym))
> >                         places-list)))
> >      `(destructuring-bind ,temps ,value-list
> >         (setf ,@(mapcan #'list places-list temps)))))
> 
> That works indeed, and detects list-length mismatches in safe
> code unlike my POP solution.
> 
> However, neither macro preserves the standard left-to-right
> evaluation order.  How difficult would it be to evaluate the
> subforms of PLACES-LIST elements before VALUE-LIST?
> [...]

Oh, you can do that with DEFINE-SETF-METHOD.  Those things are a bear to
write sometimes but they do work...  Sorry for not having thought about 
that!  I don't have time to just dash one of those off--they are serious
work to write and I'd probably have to bill you for the answer. :-)
From: Kalle Olavi Niemitalo
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <iznr8siy47w.fsf@stekt34.oulu.fi>
Kent M Pitman <······@world.std.com> writes:

> Kalle Olavi Niemitalo <···@iki.fi> writes:
> 
> > However, neither macro preserves the standard left-to-right
> > evaluation order.  How difficult would it be to evaluate the
> > subforms of PLACES-LIST elements before VALUE-LIST?
> 
> Oh, you can do that with DEFINE-SETF-METHOD.

Your committee renamed that to DEFINE-SETF-EXPANDER.  :-)

Do you mean there should be an intermediate function MY-LIST, for
which a setf expander would be defined with DEFINE-SETF-EXPANDER,
and SETF-FROM-LIST should then (setf (my-list x y) '(1 2))?
Otherwise, I don't see how DEFINE-SETF-EXPANDER is relevant here.
From: Kent M Pitman
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <sfw7kua79iv.fsf@world.std.com>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> 
> Kent M Pitman <······@world.std.com> writes:
> 
> > Kalle Olavi Niemitalo <···@iki.fi> writes:
> > 
> > > However, neither macro preserves the standard left-to-right
> > > evaluation order.  How difficult would it be to evaluate the
> > > subforms of PLACES-LIST elements before VALUE-LIST?
> > 
> > Oh, you can do that with DEFINE-SETF-METHOD.
> 
> Your committee renamed that to DEFINE-SETF-EXPANDER.  :-)

Oops.

> Do you mean there should be an intermediate function MY-LIST, for
> which a setf expander would be defined with DEFINE-SETF-EXPANDER,
> and SETF-FROM-LIST should then (setf (my-list x y) '(1 2))?
> Otherwise, I don't see how DEFINE-SETF-EXPANDER is relevant here.

You and Barry are right; you can just do it from GET-SETF-EXPANSION 
without the hair of making it general to DEFINE-SETF-EXPANDER.  And
that simplifies things a little.

I'd call the macro PLACE-LIST, not MY-LIST, but sure, you could also
do that.  I doubt anything useful would be accomplished by making such
a macro.

If I'd volunteered to actually write the code, I'd probably 
have realized my original suggestion was off-base; since I was busy
dismissing it, I didn't think very hard about it.  Sorry about that.
Ok, here's my pennance, which may still have bugs (no warranty, in 
other words) but has been lightly tested on the examples that follow:

(defmacro set-from-list (places values)
  (let ((expansion-data-list (mapcar #'(lambda (place)
                                         (multiple-value-list 
                                          (get-setf-expansion place)))
                                     places)))
    `(let ,(mapcan #'(lambda (expansion-data)
                       (mapcar #'list
                               (first  expansion-data)
                               (second expansion-data)))
                   expansion-data-list)
       (destructuring-bind ,(mapcar #'(lambda (place expansion-data)
                                        (let ((vars (third expansion-data)))
                                          (unless (= (length vars) 1)
                                            (error "Can't SET-FROM-LIST ~S."
                                                    place))
                                          (first vars)))
                                    places expansion-data-list)
           ,values
         ,@(mapcar #'fourth expansion-data-list)))))

For example (from LispWorks 4.1; implementations might vary slightly
in what these expansion look like):

(pprint (macroexpand-1 '(set-from-list ((car x) (cdr x)) '(1 2))))

(LET ((#:SUBFORM477 X) (#:SUBFORM479 X))
  (DESTRUCTURING-BIND (#:NEW-VALUE478 #:NEW-VALUE480)
                      '(1 2)
                      (SEQ::SET-CAR #:SUBFORM477 #:NEW-VALUE478)
                      (SEQ::SET-CDR #:SUBFORM479 #:NEW-VALUE480)))

(pprint (macroexpand-1 '(set-from-list ((car (setq x y))
                                        (cdr x))
                          (progn (print x)
                                 '(1 2)))))

(LET ((#:SUBFORM481 (SETQ X Y)) (#:SUBFORM483 X))
  (DESTRUCTURING-BIND (#:NEW-VALUE482 #:NEW-VALUE484)
                      (PROGN (PRINT X) '(1 2))
                      (SEQ::SET-CAR #:SUBFORM481 #:NEW-VALUE482)
                      (SEQ::SET-CDR #:SUBFORM483 #:NEW-VALUE484)))

That seems to preserve the side-effect order.  e.g.:

(let ((y (cons 3 4)) (x nil))
  (print x)
  (set-from-list ((car (setq x y)) 
	          (cdr x))
    (progn (print x) '(1 2)))
  x)

NIL 
(3 . 4) 
=> (1 . 2)
From: Dr. Edmund Weitz
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <m37kuaibd9.fsf@bird.agharta.de>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> However, neither macro preserves the standard left-to-right
> evaluation order.  How difficult would it be to evaluate the
> subforms of PLACES-LIST elements before VALUE-LIST?
> 
>   (let ((x '()))
>     (set-from-list ((cdr (push 42 x))) (copy-list x))
>     ;; which means: (setf (cdr (push 42 x)) (first x))
>     x)  ; should be (42 . 42)

OK, I tried my luck and provide two versions below. I haven't tested
them extensively but they work with your example above as well as with
some simple test cases that I came up with myself on LispWorks
Personal and CMUCL.

The first version does the job but assumes that PLACES and VALUES have
the same length. The second version tries to behave reasonably in case
of a mismatch: If there are more values than places, it returns the
rest of the list. If there are more places than values it'll either
leave the remaining places untouched or set them to the FILL-FORM
argument if it was provided.

Note that this was the first time I played around with LOOP and
GET-SETF-METHOD, so please bear with me. Your corrections and comments
are welcome.

Edi.

PS: Formatting might look a bit strange 'cause I _tried_ to preserve
the 72-column limit.


;; first version
(defmacro setf-from-list (places values)
  (let ((=list-val= (gensym)))
    (let (vars forms var set access)
      (loop for place in places
            do (multiple-value-setq (vars forms var set access)
                   (get-setf-method place))
            append (mapcar #'list vars forms) into place-bindings
            collect `(,(car var) (pop ,=list-val=)) into temp-bindings
            collect set into assignments
            finally (progn
                      (return `(let* ,place-bindings
                                 (let ((,=list-val= ,values))
                                   (let* ,temp-bindings
                                     ,@assignments)))))))))

;; second version
(defmacro setf-from-list (places values 
                                 &key 
                                 (fill-form nil supplied-fill-form-p))
  (let ((=list-val= (gensym))
        (=list-len= (gensym))
        (=excess-len= (gensym)))
    (let (vars forms var set access)
      (loop for place in places
            do (multiple-value-setq (vars forms var set access)
                   (get-setf-method place))
            append (mapcar #'list vars forms) into place-bindings
            collect `(,(car var) (pop ,=list-val=)) into temp-bindings
            collect `(when (>= (decf ,=list-len=) 0) ,set) 
                    into assignments
            finally (progn
                      (return `(let* ,(append place-bindings
                                              `((,=list-val= ,values)
                                                (,=list-len= 
                                                 (length ,=list-val=))))
                                 ,(if supplied-fill-form-p
                                      `(let ((,=excess-len= 
                                              (- ,(length places)
                                                 ,=list-len=)))
                                         (when (> ,=excess-len= 0)
                                           (setq ,=list-val=
                                                 (nconc ,=list-val=
                                                        (make-list 
                                                         ,=excess-len=
                                                         :initial-element
                                                         ,fill-form)))
                                           (incf ,=list-len=
                                                 ,=excess-len=))))
                                 (let* ,temp-bindings
                                   ,@assignments)
                                 ,=list-val=)))))))
From: Erik Haugan
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <873d4ziqbj.fsf@kometknut.neitileu.no>
* ···@agharta.de (Dr. Edmund Weitz)
> I understand that what I'm asking for in the subject line is a special
> form and that I can't create such a thing. But I still think there
> must be better solution to my problem than the one that I came up
> with. Here it is:
> 
> I've written a macro that basically looks like this:
> 
> (defmacro set-from-list (places-list value-list)
>   `(progn
>      ,@(mapcar #'(lambda (place value)
>                    `(setf ,place ,value))
>                places-list (eval value-list))))
> 
> The idea is that I'll be able to say things like
> 
> (set-from-list (x y) '(1 2))
> 
> resulting in 1 being assigned to x and 2 being assigned to y. What
> bugs me is that I have to call eval while every book says I should
> avoid it like the plague. Is there a better way to do this?

Eval won't hang around in the compiled code, so that's not a problem.
However, it is quite possible that eval won't do what you expect.  For
instance, consider the following code:

(let ((some-values '(1 2)
  (set-from-list (x y) some-values)
  (+ x y))))

It won't work because eval evaluates it's argument in the null lexical
environment, where some-values is unbound.  Also, the dynamic environment
will be the environment at macro expansion time, which is probably not what
you want.

It seems to me that Kalle Olavi Niemital has got it right in his proposal.

Erik
From: Kalle Olavi Niemitalo
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <izny9mrleew.fsf@stekt34.oulu.fi>
Erik Haugan <····@haugan.no> writes:

> It seems to me that Kalle Olavi Niemital has got it right in his proposal.

  (let ((case-fold-search nil))
    (when (string-match (regexp-quote "%-20,20n") gnus-summary-line-format)
      (setq gnus-summary-line-format
  	    (replace-match "%-21,21n" t t gnus-summary-line-format))))

Hmm... Perhaps I should write a with-string-as-buffer (string-place
&rest body) macro.
From: Kalle Olavi Niemitalo
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <izn1ykj3eiw.fsf@stekt34.oulu.fi>
···@agharta.de (Dr. Edmund Weitz) writes:

> (set-from-list (x y) '(1 2))

  (defmacro set-from-list (places values-form)
    ;; PLACES is (X Y)
    ;; VALUES-FORM is a form that returns a list
    (let ((=values= (gensym)))
      `(let ((,=values= ,values-form))
  	 ,@(loop for place in places
  		 collect `(setf ,place (pop ,=values=))))))

Then your example expands to:

  (let ((#:G1151 '(1 2)))
    (setf x (pop #:G1151))
    (setf y (pop #:G1151)))

It might be simpler to use MULTIPLE-VALUE-SETQ with VALUES-LIST, but
then you'd be restricted by how many values the Lisp implementation
supports.

Try DESTRUCTURING-BIND for the LET-like bindings you mentioned in
another article.
From: Kalle Olavi Niemitalo
Subject: initial value of *PRINT-CIRCLE*
Date: 
Message-ID: <iznr8sjjp80.fsf_-_@stekt34.oulu.fi>
Kalle Olavi Niemitalo <···@iki.fi> writes:

>   (let ((#:G1151 '(1 2)))
>     (setf x (pop #:G1151))
>     (setf y (pop #:G1151)))

...where each #:G1151 is the same symbol, of course.

The initial value of *PRINT-CIRCLE* is documented to be false.
If I made an init file that changed it to true, would I break
some conforming programs?
From: Barry Margolin
Subject: Re: initial value of *PRINT-CIRCLE*
Date: 
Message-ID: <Sc1v7.10$5h1.553@burlma1-snr2>
In article <··················@stekt34.oulu.fi>,
Kalle Olavi Niemitalo  <···@iki.fi> wrote:
>Kalle Olavi Niemitalo <···@iki.fi> writes:
>
>>   (let ((#:G1151 '(1 2)))
>>     (setf x (pop #:G1151))
>>     (setf y (pop #:G1151)))
>
>...where each #:G1151 is the same symbol, of course.

Of course.  It's common in informal communication to use notation like that
and the reader will assume that similar gensyms are the same ones.

>The initial value of *PRINT-CIRCLE* is documented to be false.
>If I made an init file that changed it to true, would I break
>some conforming programs?

I don't think so.  CL specifies the initial default value of the
printer/reader control variables, but users and programs are permitted to
change them (e.g. if you like to type octal numbers, you can set
*READ-BASE*).  Applications that depend on a particular setting should bind
them to what they want, or use WITH-STANDARD-IO-SYNTAX to get all the
standard settings.

I also don't think setting *PRINT-CIRCLE* to true could break anything.
Enabling this increases read/print consistency, and I can't imagine a
program that depends on *in*consistency.

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Erik Naggum
Subject: Re: initial value of *PRINT-CIRCLE*
Date: 
Message-ID: <3211209388543477@naggum.net>
* Kalle Olavi Niemitalo <···@iki.fi>
| The initial value of *PRINT-CIRCLE* is documented to be false.  If I made
| an init file that changed it to true, would I break some conforming
| programs?

  No.  Any conforming program worth talking abot that depends on it being
  false will have bound it to false.  That is what software quality is all
  about.  Some programmers who do not personally like the standard have a
  tendency to expect other programmers to honor their irrational dislikes
  and try to break other people's code on purpose when they have bound some
  printer control variable to something that is perfectly within the bounds
  of the standard and which could be a reasonable thing to do.  If you find
  such bugs, consider it a very serious conformance bug and demand that the
  vendor fix it.  Also strongly suggest that they remove the programmer who
  has personal gripes with the standard from code that you need to trust,
  and go over it with someone who _cares_ about following specifications,
  because such bugs will recur in his code and you have to test everything,
  which is simply not worth your time or money when you pay for a product.

///
From: Kent M Pitman
Subject: Re: initial value of *PRINT-CIRCLE*
Date: 
Message-ID: <sfw3d4zgs9r.fsf@world.std.com>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> 
> Kalle Olavi Niemitalo <···@iki.fi> writes:
> 
> >   (let ((#:G1151 '(1 2)))
> >     (setf x (pop #:G1151))
> >     (setf y (pop #:G1151)))
> 
> ...where each #:G1151 is the same symbol, of course.

I do this sometimes, but remember it's not going to handle error checking
well (mismatch between list length and number of places).  The 
destructuring-bind example I gave does handle error checking because it's
built into destructuring-bind.

> The initial value of *PRINT-CIRCLE* is documented to be false.
> If I made an init file that changed it to true, would I break
> some conforming programs?

[Is this related?]  Conforming programs that care about the binding of
*print-circle* should be binding it themselves, I feel.  Nothing says
it won't have its value changed, and it's quite obviously a
user-preference thing.  However, a program still conforms even if it
has a bug in it due to this--the only way to tell lif you've broken
anything is to ask the programmer his intent.  For example, you'll
change what (princ-to-string '(quote foo)) returns and that could
affect programs, but whether it will break the program depends on
whether the program is looking at the string for its specific
characters (which have changed) or for its ability to re-read the same
(which has not changed).

Nevertheless, when you fudge with option variables you should expect some
code is not streamlined against it.  Setting *print-case* shouldn't really
affect things either, but MANY programs are not safeguarded against that.
Ditto with *print-length* and *print-level*.  But bugs due to
*print-circle* are less common in my experience.
From: Kalle Olavi Niemitalo
Subject: Re: initial value of *PRINT-CIRCLE*
Date: 
Message-ID: <87r8sjdvw9.fsf@Astalo.y2000.kon.iki.fi>
Kent M Pitman <······@world.std.com> writes:

> [Is this related?]

Well, I checked the expansion with CLISP and somehow assumed it
would print in #1# style.  When I noticed what I had posted, I
thought of how I could make my assumption correct next time.
From: Kaz Kylheku
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <iZbv7.40758$ob.1133278@news1.rdc1.bc.home.com>
In article <··············@bird.agharta.de>, Dr. Edmund Weitz wrote:
>The idea is that I'll be able to say things like
>
>(set-from-list (x y) '(1 2))
>
>resulting in 1 being assigned to x and 2 being assigned to y. What
>bugs me is that I have to call eval while every book says I should
>avoid it like the plague. Is there a better way to do this?

Try this:

(defmacro set-from-list (places-list value-list)
 (if (and (listp value-list) (eq (first value-list) 'quote))
  `(setf ,@(mapcan #'(lambda (place value) 
                    `(,place ',value)) places-list (second value-list)))
  (let ((iterator (gensym)))
   `(let ((,iterator ,value-list))
     ,@(mapcan #'(lambda (place) 
                  `((setf ,place (car ,iterator))
                    (setf ,iterator (cdr ,iterator))))
       places-list)))))

This implements two strategies: it does one thing when the parameter
value-list is a quoted list, and a falls back on an alternative when
the parameter is it's something else, like a symbol or some other form
that (supposedly) evaluates to a list.

Thus    
  
  (set-from-list (a b c) '(1 2 (3 4)))

is transformed to

  (setf a '1 b '2 c '(3 4)) ;; could be a compiler macro

and     

  (set-from-list (a b c) foo)

is transformed into something like:

  (let ((#:G7 foo))
   (setf a (car #:G7))
   (setf #:G7 (cdr #:G7))
   (setf b (car #:G7))
   (setf #:G7 (cdr #:G7))
   (setf c (car #:G7))
   (setf #:G7 (cdr #:G7))) ;; wasted step---could be chopped by  macro

As you can see, the problem is that unless the value list is a quoted
literal, the macro doesn't have explicit knowledge of its contents at
macro expansion time. So it's necessary to emit some kind of implicit
references to the contents of the list, by taking the form which produces
the list, evaluating it exactly once to produce a list value that is
bound to a gensym'd local and then referring to the list object through
that local.
From: Kaz Kylheku
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <Bkcv7.40784$ob.1135507@news1.rdc1.bc.home.com>
In article <··············@bird.agharta.de>, Dr. Edmund Weitz wrote:
>The idea is that I'll be able to say things like
>
>(set-from-list (x y) '(1 2))
>
>resulting in 1 being assigned to x and 2 being assigned to y. What
>bugs me is that I have to call eval while every book says I should
>avoid it like the plague. Is there a better way to do this?

Try this:

(defmacro set-from-list (places-list value-list)
 (if (and (listp value-list) (eq (first value-list) 'quote))
  `(setf ,@(mapcan #'(lambda (place value) 
                    `(,place ',value)) places-list (second value-list)))
  (let ((iterator (gensym)))
   `(let ((,iterator ,value-list))
     ,@(mapcan #'(lambda (place) 
                  `((setf ,place (car ,iterator))
                    (setf ,iterator (cdr ,iterator))))
       places-list)))))

This implements two strategies: it does one thing when the parameter
value-list is a quoted list, and a falls back on an alternative when
the parameter is something else, like a symbol or some other form
that (supposedly) evaluates to a list.

Thus    
  
  (set-from-list (a b c) '(1 2 (3 4)))

is transformed to

  (setf a '1 b '2 c '(3 4)) ;; could be a compiler macro

and     

  (set-from-list (a b c) foo)

is transformed into something like:

  (let ((#:G7 foo))
   (setf a (car #:G7))
   (setf #:G7 (cdr #:G7))
   (setf b (car #:G7))
   (setf #:G7 (cdr #:G7))
   (setf c (car #:G7))
   (setf #:G7 (cdr #:G7))) ;; wasted step---could be chopped by  macro

As you can see, the problem is that unless the value list is a quoted
literal, the macro doesn't have explicit knowledge of its contents at
macro expansion time. So it's necessary to emit some kind of implicit
references to the contents of the list, by taking the form which produces
the list, evaluating it exactly once to produce a list value that is
bound to a gensym'd local and then referring to the list object through
that local.
From: Kalle Olavi Niemitalo
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <87d7426s6t.fsf@Astalo.y2000.kon.iki.fi>
···@ashi.footprints.net (Kaz Kylheku) writes:

>    (setf c (car #:G7))
>    (setf #:G7 (cdr #:G7))) ;; wasted step---could be chopped by  macro

Could be chopped by the compiler too, as #:G7 isn't used after
that and CAR would already have caught any type mismatch.
Does any compiler actually optimize this?  CMUCL doesn't.
From: Kaz Kylheku
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <hlcv7.40788$ob.1135507@news1.rdc1.bc.home.com>
In article <··············@bird.agharta.de>, Dr. Edmund Weitz wrote:
>The idea is that I'll be able to say things like
>
>(set-from-list (x y) '(1 2))
>
>resulting in 1 being assigned to x and 2 being assigned to y. What
>bugs me is that I have to call eval while every book says I should
>avoid it like the plague. Is there a better way to do this?

Try this:

(defmacro set-from-list (places-list value-list)
 (if (and (listp value-list) (eq (first value-list) 'quote))
  `(setf ,@(mapcan #'(lambda (place value) 
                    `(,place ',value)) places-list (second value-list)))
  (let ((iterator (gensym)))
   `(let ((,iterator ,value-list))
     ,@(mapcan #'(lambda (place) 
                  `((setf ,place (car ,iterator))
                    (setf ,iterator (cdr ,iterator))))
       places-list)))))

This implements two strategies: it does one thing when the parameter
value-list is a quoted list, and a falls back on an alternative when
the parameter is it's something else, like a symbol or some other form
that (supposedly) evaluates to a list.

Thus    
  
  (set-from-list (a b c) '(1 2 (3 4)))

is transformed to

  (setf a '1 b '2 c '(3 4)) ;; could be a compiler macro

and     

  (set-from-list (a b c) foo)

is transformed into something like:

  (let ((#:G7 foo))
   (setf a (car #:G7))
   (setf #:G7 (cdr #:G7))
   (setf b (car #:G7))
   (setf #:G7 (cdr #:G7))
   (setf c (car #:G7))
   (setf #:G7 (cdr #:G7))) ;; wasted step---could be chopped by  macro

As you can see, the problem is that unless the value list is a quoted
literal, the macro doesn't have explicit knowledge of its contents at
macro expansion time. So it's necessary to emit some kind of implicit
references to the contents of the list, by for instance taking the form
which produces the list, evaluating it exactly once to produce a list
value that is bound to a gensym'd local and then referring to the list
object through that local.
From: Sam Steingold
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <uvghu9fs7.fsf@xchange.com>
> * In message <··············@bird.agharta.de>
> * On the subject of "Macros that evaluate some of their arguments"
> * Sent on 04 Oct 2001 10:12:29 +0200
> * Honorable ···@agharta.de (Dr. Edmund Weitz) writes:
>
> The idea is that I'll be able to say things like
> 
> (set-from-list (x y) '(1 2))
> 
> resulting in 1 being assigned to x and 2 being assigned to y. What
> bugs me is that I have to call eval while every book says I should
> avoid it like the plague. Is there a better way to do this?

(defmacro set-from-list (places values)
  (let ((gens (mapcar (lambda (x) (declare (ignore x)) (gensym)) places)))
    `(destructuring-bind ,gens ,values
       (setf ,@(mapcan #'list places gens)))))

> PS: I know that in the example above I can simply remove the call to
> eval and call the macro like
> (set-from-list (x y) (1 2))

then you could have used this:

(defmacro set-from-list (places values)
  `(setf ,@(mapcan #'list places values)))


PS.  I see things like
        (mapcar (lambda (x) (declare (ignore x)) (gensym)) LIST)
so often that I start to wonder why not make (gensym LIST) return the
same as the above MAPCAR.  Kent?

-- 
Sam Steingold (http://www.podval.org/~sds)
Support Israel's right to defend herself! <http://www.i-charity.com/go/israel>
Read what the Arab leaders say to their people on <http://www.memri.org/>
"Complete Idiots Guide to Running LINUX Unleashed in a Nutshell for Dummies"
From: Kent M Pitman
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <sfwk7yahtci.fsf@world.std.com>
Sam Steingold <···@gnu.org> writes:

> 
> > * In message <··············@bird.agharta.de>
> > * On the subject of "Macros that evaluate some of their arguments"
> > * Sent on 04 Oct 2001 10:12:29 +0200
> > * Honorable ···@agharta.de (Dr. Edmund Weitz) writes:
> >
> > The idea is that I'll be able to say things like
> > 
> > (set-from-list (x y) '(1 2))
> > 
> > resulting in 1 being assigned to x and 2 being assigned to y. What
> > bugs me is that I have to call eval while every book says I should
> > avoid it like the plague. Is there a better way to do this?
> 
> (defmacro set-from-list (places values)
>   (let ((gens (mapcar (lambda (x) (declare (ignore x)) (gensym)) places)))
>     `(destructuring-bind ,gens ,values
>        (setf ,@(mapcan #'list places gens)))))
> 
> > PS: I know that in the example above I can simply remove the call to
> > eval and call the macro like
> > (set-from-list (x y) (1 2))

Uh, the problem here is that value is (1 2) and will give you an illegal
function error.  I assume this whole exercise is about the fact that the
values-producing form is a single expression.  If it's just a list of 
expressions, one might as well not bother with the thing below, since
 (setf x 1 y 2)
is easier.  
 
> then you could have used this:
> 
> (defmacro set-from-list (places values)
>   `(setf ,@(mapcan #'list places values)))

Hmm.  The following is probably not going to compile well, doesn't 
error-check too many/few values, and may have limitations due to argument
values, but I observe it anyway mostly because it illustrates a little-known
fact about how to use symbol-macrolet:

 (defmacro set-from-list (places values)
   (let ((temps (mapcar #'(lambda (x) (declare (ignore x)) (gensym)) places)))
     ;; KLUDGE ALERTS:
     ;; (1) Tricks MULTIPLE-VALUE-SETQ into being MULTIPLE-VALUE-SETF
     ;; (2) Makes use of its special knowledge that each place will be used
     ;;     only once and in the right order, so intermediate temps are not
     ;;     needed explicitly to preserve left-to-right order nor single
     ;;     in the symbol-macrolet expansion.  (MULTIPLE-VALUE-SETQ has a 
     ;;     similar issue to solve again for itself which has to be solved
     ;;     differently.)
     `(symbol-macrolet ,(mapcar #'list temps places)
        (multiple-value-setq ,temps (values-list ,values)))))

Doing tha above tricks MULTIPLE-VALUE-SETQ into doing all the setf
expansion stuff. Of course, it relies on the number of values being
small, but unless you've made an error, it will be in one-to-one
correspondence with the list of places, which if created by a human
will be short.  (If created by macro, all bets are off...)

A few tests from upthread to see if I'm on the right track:

 (let (x y) (set-from-list (x y) '(1 2)) (list x y))
 => (1 2)

 (let ((x '()))
   (set-from-list ((cdr (push 42 x))) (copy-list x))
   ;; which means: (setf (cdr (push 42 x)) (first x))
   x)
 => (42 . 42)

> 
> 
> PS.  I see things like
>         (mapcar (lambda (x) (declare (ignore x)) (gensym)) LIST)
> so often that I start to wonder why not make (gensym LIST) return the
> same as the above MAPCAR.  Kent?

Well, we can't change the spec now.

But you can define a GENSYMS function that does that.
From: Tim Moore
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <9pkvnv$ce0$0@216.39.145.192>
In article <···············@world.std.com>, "Kent M Pitman"
<······@world.std.com> wrote:
> Hmm.  The following is probably not going to compile well, doesn't
> error-check too many/few values, and may have limitations due to
> argument values, but I observe it anyway mostly because it illustrates a
> little-known fact about how to use symbol-macrolet:
>  (defmacro set-from-list (places values)
>    (let ((temps (mapcar #'(lambda (x) (declare (ignore x)) (gensym))
>    places)))
>      ;; KLUDGE ALERTS:
>      ;; (1) Tricks MULTIPLE-VALUE-SETQ into being MULTIPLE-VALUE-SETF ;;
>      (2) Makes use of its special knowledge that each place will be used
>      ;;     only once and in the right order, so intermediate temps are
>      not ;;     needed explicitly to preserve left-to-right order nor
>      single ;;     in the symbol-macrolet expansion. 
>      (MULTIPLE-VALUE-SETQ has a ;;     similar issue to solve again for
>      itself which has to be solved ;;     differently.)
>      `(symbol-macrolet ,(mapcar #'list temps places)
>         (multiple-value-setq ,temps (values-list ,values)))))
> Doing tha above tricks MULTIPLE-VALUE-SETQ into doing all the setf
> expansion stuff. Of course, it relies on the number of values being
> small, but unless you've made an error, it will be in one-to-one
> correspondence with the list of places, which if created by a human will
> be short.  (If created by macro, all bets are off...)  A few tests from
You can do this with a bit less hair:
(defmacro set-from-list (places values )
  `(setf (values ,@places) (values-list ,values)))

Tim
From: Kaz Kylheku
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <7Esv7.43209$ob.1165432@news1.rdc1.bc.home.com>
In article <············@216.39.145.192>, Tim Moore wrote:
> (defmacro set-from-list (places values )
>  `(setf (values ,@places) (values-list ,values)))

Bravo!
From: Kent M Pitman
Subject: Re: Macros that evaluate some of their arguments
Date: 
Message-ID: <sfwu1xdmssf.fsf@world.std.com>
···@ashi.footprints.net (Kaz Kylheku) writes:

> In article <············@216.39.145.192>, Tim Moore wrote:
> > (defmacro set-from-list (places values )
> >  `(setf (values ,@places) (values-list ,values)))
> 
> Bravo!

Aha...  I'd known some dialects had had SETF of VALUES, but I forgot we had
put that into CL.  That's why my responses had gone the long way around.
Thanks for the reminder, Tim!

However, short and to the point as this one is, do keep in mind that 
it's subject to the same caveats as my SYMBOL-MACROLET solution:
 (a) this won't check for an overrun or underrun of values
 (b) if a really lot of values are produced, values-list may not be able
     to turn the values into n values even though only a subset of the n
     values are being received (which might matter in some implementations
     and not in others, depending on whether the values producer is smart
     enough to never generate the values no one is listening for).