From: Dr. Edmund Weitz
Subject: SET, SETQ, SETF confusion
Date: 
Message-ID: <m3eloii57k.fsf@bird.agharta.de>
Hello!

One of the first solutions to my SET-FROM-LIST problem (see
<···················@bird.agharta.de>) was this one:

(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))))

As some posters immediately remarked, SET affects only the
SYMBOL-VALUE and thus this macro would be useless in a lexical context
like so:

* (let (x y)
    (set-from-list (x y) '(1 2)) (list x y))
(NIL NIL)

My first na�ve reaction was to replace the SET in the macro above by
SETQ but it didn't work, i.e. the test case above produced the same
(NIL NIL) output.

From one of KMP's remarks I conclude that the problem stems from
QUOTEing the PLACES-LIST, but I don't fully understand what's
happening here. As far as I understand it, the first argument to
MAPCAR above is '(X Y) which is a list of _symbols_, so the call to
MAPCAR should evaluate (SETQ X 1) and (SETQ Y 2), but when these forms
are evaluated, X and Y seem to have lost their lexical bindings
magically.

Also, when SETQ-FROM-LIST (so-to-say) is executed, if it doesn't
change the lexical bindings of X and Y provided by the LET form around
it, what _does_ it do instead? If I type X into the listener _after_
evaluating the LET test case, I am told that the variable X is
unbound. If, instead, I create a SPECIAL variable X _before_ I
evaluate the LET form, it isn't changed either...

Does the test case change bindings in some private parallel universe
or does it do nothing? And why am I not getting at least an error
message? As you can see, I'm thoroughly confused.

Thanks for your help,
Edi.

PS: I know that the answer can be found in the CLHS somewhere. But the
CLHS is really _large_ and I would be grateful if someone could
provide some cues.

From: Kaz Kylheku
Subject: Re: SET, SETQ, SETF confusion
Date: 
Message-ID: <qBjv7.41296$ob.1146219@news1.rdc1.bc.home.com>
In article <··············@bird.agharta.de>, Dr. Edmund Weitz wrote:
>Hello!
>
>One of the first solutions to my SET-FROM-LIST problem (see
><···················@bird.agharta.de>) was this one:
>
>(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))))

[ snip ]

>From one of KMP's remarks I conclude that the problem stems from
>QUOTEing the PLACES-LIST, but I don't fully understand what's
>happening here. As far as I understand it, the first argument to
>MAPCAR above is '(X Y) which is a list of _symbols_,

No, the argument to mapcar is (quote (x y)), which is a two
element list containing quote and (x y).   There is no need
for quoting because the list isn't being evaluated as a form;
all that is needed is ,places-list so that the parameter is
evaluted to the list is stands for.

Also, the binding of value list to a gensym'd variable is superfluous.
You get something like this

  (let ((#:G7 argument))
   (mapcar ... #:G7))

which is a long-winded way of saying:

  (mapcar ... argument)

Either way, argument is evaluated once and its value propagated to the
right place.  So the whole macro can be rewritten:

(defmacro set-from-list (places-list value-list)
  `(mapcar #'(lambda (place value)
               (set place value))
     (quote ,places-list) ,value-list))

>Also, when SETQ-FROM-LIST (so-to-say) is executed, if it doesn't
>change the lexical bindings of X and Y provided by the LET form around
>it, what _does_ it do instead?  If I type X into the listener _after_
>evaluating the LET test case, I am told that the variable X is
>unbound. If, instead, I create a SPECIAL variable X _before_ I
>evaluate the LET form, it isn't changed either...

If we change the set to setq, the problem is that then all the mapcar
loop does is assign successive values to the symbol PLACE:  (setq place
value). The second argument is not evaluated! So that is where your
values disappeared: into the local variable place of the closure. :)
From: Dr. Edmund Weitz
Subject: Re: SET, SETQ, SETF confusion
Date: 
Message-ID: <m34rpei1h5.fsf@bird.agharta.de>
···@ashi.footprints.net (Kaz Kylheku) writes:

> If we change the set to setq, the problem is that then all the
>> mapcar loop does is assign successive values to the symbol PLACE:
> (setq place value). The second argument is not evaluated! So that is
> where your values disappeared: into the local variable place of the
> closure. :)

Oh my!!! Didn't I say I was confused? :)

Thanks for clearing this up. It is perfectly clear now but I was
obviously a couple of miles in the wrong direction already...

> No, the argument to mapcar is (quote (x y)), which is a two element
> list containing quote and (x y).  There is no need for quoting
> because the list isn't being evaluated as a form; all that is needed
> is ,places-list so that the parameter is evaluted to the list is
> stands for.

This I'm not sure of:

CL-USER 1 > (defmacro setq-from-list (places-list value-list)
  (let ((var (gensym)))
    `(let ((,var ,value-list))
       (mapcar #'(lambda (place value)
                   (print place)         ;; added this line
                   (setq place value))
                 (quote ,places-list) ,var))))
SETQ-FROM-LIST

CL-USER 2 > (let (x y)
    (setq-from-list (x y) '(1 2)) (list x y))

X 
Y 
(NIL NIL)

CL-USER 3 > (pprint (macroexpand-1 '(setq-from-list (x y) '(1 2))))

(LET ((#:G487 '(1 2)))
  (MAPCAR #'(LAMBDA (PLACE VALUE)
              (PRINT PLACE)
              (SETQ PLACE VALUE))
          '(X Y)
          #:G487))

CL-USER 4 > 

Thanks,
Edi.
From: Kaz Kylheku
Subject: Re: SET, SETQ, SETF confusion
Date: 
Message-ID: <12kv7.41408$ob.1146808@news1.rdc1.bc.home.com>
In article <··············@bird.agharta.de>, Dr. Edmund Weitz wrote:
>> No, the argument to mapcar is (quote (x y)), which is a two element
>> list containing quote and (x y).  There is no need for quoting
>> because the list isn't being evaluated as a form; all that is needed
>> is ,places-list so that the parameter is evaluted to the list is
>> stands for.
>
>This I'm not sure of:

Oops, you are right; I seem to have forgot that this is in the
expansion, where it will be evaluated again! Sorry about that.
From: Kent M Pitman
Subject: Re: SET, SETQ, SETF confusion
Date: 
Message-ID: <sfw669urrz9.fsf@world.std.com>
···@ashi.footprints.net (Kaz Kylheku) writes:

> 
> In article <··············@bird.agharta.de>, Dr. Edmund Weitz wrote:
> >> No, the argument to mapcar is (quote (x y)), which is a two element
> >> list containing quote and (x y).  There is no need for quoting
> >> because the list isn't being evaluated as a form; all that is needed
> >> is ,places-list so that the parameter is evaluted to the list is
> >> stands for.
> >
> >This I'm not sure of:
> 
> Oops, you are right; I seem to have forgot that this is in the
> expansion, where it will be evaluated again! Sorry about that.

Mine should do the right thing.  One virtue of doing it the "right" 
way instead of "ad hoc" ways is that it automatically handles the special
cases.

I'll paste it again so you don't lose it.  By starting a new thread
instead of continuing the previous one, you made it harder to find.

(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)))))
From: Dr. Edmund Weitz
Subject: Re: SET, SETQ, SETF confusion
Date: 
Message-ID: <m3sncyxdrd.fsf@bird.agharta.de>
Kent M Pitman <······@world.std.com> writes:

> I'll paste it again so you don't lose it.  By starting a new thread
> instead of continuing the previous one, you made it harder to find.

Yeah, but I started this new thread because I had another question
that wasn't really related to the original SET-FROM-LIST thing. It
turned out that I was just confused and my question was a dumb one.

Edi.