From: Adam Warner
Subject: @ list splicing bug?
Date: 
Message-ID: <pan.2003.11.26.02.24.43.616311@consulting.net.nz>
Hi all,

Should the evaluation of:
``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))

Be:
'((cons 'a a) (cons 'b b) (cons 'c c))

CMUCL and SBCL return `((cons 'a a)).

I've distilled this example from one of the macros I have written that has
returned unexpected results. Before reporting this bug I just want to
check that my example is portably defined ANSI Common Lisp code and the
result CMUCL and SBCL returns is not conforming.

Thanks,
Adam

From: Kent M Pitman
Subject: Re: @ list splicing bug?
Date: 
Message-ID: <sfwekvvoeyn.fsf@shell01.TheWorld.com>
Adam Warner <······@consulting.net.nz> writes:

> Hi all,
> 
> Should the evaluation of:
> ``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))
> 
> Be:
> '((cons 'a a) (cons 'b b) (cons 'c c))
> 
> CMUCL and SBCL return `((cons 'a a)).

FWIW, LW 4.2.7 returns 

(QUOTE ((CONS 'A A) (CONS 'B B) (CONS 'C C)))

but I'm not sure this is really right.  The expression seems ill-formed
since you have to do outer-backquote/inner-comma forms first, and after
the first evaluation you get

 `(,(quote (cons 'a a) (cons 'b b) (cons 'c c)))

and I'm not sure that's really even well-formed.

NOTE that ,,@blah is well-defined and tends to mean (conceptually) 
 (mapcar #'comma blah)
but although ,' usually means simply to suppress an evaluation layer
it doesn't combine to mean to mean that ,',@ means
 (mapcar #'identity ,blah)

I think you want to write
 ``(,,@(loop for arg in '(a b c) collect `'(cons ',arg ,arg)))
for which LW 4.2.7 returns
 (SYSTEM::BQ-LIST (QUOTE (CONS (QUOTE A) A)) (QUOTE (CONS (QUOTE B) B)) (QUOTE (CONS (QUOTE C) C)))
which pretty prints as
 `((CONS (QUOTE A) A) (CONS (QUOTE B) B) (CONS (QUOTE C) C))
Presumably the compiler will simplify this to:
 '((CONS (QUOTE A) A)
   (CONS (QUOTE B) B)
   (CONS (QUOTE C) C))

> I've distilled this example from one of the macros I have written
> that has returned unexpected results. Before reporting this bug I 
> just want to check that my example is portably defined ANSI Common 
> Lisp code and the result CMUCL and SBCL returns is not conforming.

It looks dubious to me, but it's late and I try to avoid purporting
to have an informed viewpoint at this hour...
From: Adam Warner
Subject: Re: @ list splicing bug?
Date: 
Message-ID: <pan.2003.11.26.07.20.48.881563@consulting.net.nz>
Hi Kent M Pitman,

>> Should the evaluation of:
>> ``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))
>> 
>> Be:
>> '((cons 'a a) (cons 'b b) (cons 'c c))
>> 
>> CMUCL and SBCL return `((cons 'a a)).
> 
> FWIW, LW 4.2.7 returns 
> 
> (QUOTE ((CONS 'A A) (CONS 'B B) (CONS 'C C)))
> 
> but I'm not sure this is really right.  The expression seems ill-formed
> since you have to do outer-backquote/inner-comma forms first, and after
> the first evaluation you get
> 
>  `(,(quote (cons 'a a) (cons 'b b) (cons 'c c)))
> 
> and I'm not sure that's really even well-formed.

Thank you for your exceptional analysis Kent and Peter. As QUOTE operates
upon a single object I can understand the error in the expansion.

...

> I think you want to write
>  ``(,,@(loop for arg in '(a b c) collect `'(cons ',arg ,arg)))
                                            ^
This turned out to be the correct approach! |
                                            +--The critical addition.
Many thanks,
Adam
From: Kaz Kylheku
Subject: Re: @ list splicing bug?
Date: 
Message-ID: <cf333042.0311260617.7d9c1e4d@posting.google.com>
Adam Warner <······@consulting.net.nz> wrote in message news:<······························@consulting.net.nz>...
> Hi all,
> 
> Should the evaluation of:
> ``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))
> 
> Be:
> '((cons 'a a) (cons 'b b) (cons 'c c))

Note that 

  ,',@X 

means 

  ,(QUOTE ,@X)

So if X is the list ((cons 'a a) (cons 'b 'b)) you get

  ,(QUOTE (CONS 'A A) (CONS 'B B))

In other words, you have spliced the list into the QUOTE form such
that QUOTE is called with each element of the list as a separate
argument. But QUOTE takes only one argument: an object to be quoted.

Sometimes it really helps to drop the syntactic sugar and see the
QUOTE. :)
From: Peter Seibel
Subject: Re: @ list splicing bug?
Date: 
Message-ID: <m3oeuz3avr.fsf@javamonkey.com>
Adam Warner <······@consulting.net.nz> writes:

> Hi all,
> 
> Should the evaluation of:
> ``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))
> 
> Be:
> '((cons 'a a) (cons 'b b) (cons 'c c))
> 
> CMUCL and SBCL return `((cons 'a a)).
> 
> I've distilled this example from one of the macros I have written that has
> returned unexpected results. Before reporting this bug I just want to
> check that my example is portably defined ANSI Common Lisp code and the
> result CMUCL and SBCL returns is not conforming.

Here's you're problem I think. Following the rules of section 2.4.6
Backquote (plus a bit of semantic tidying to keep the thing from
getting huge) here's what your original expression derives to:

  ``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))
  ``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg . nil)))
  ``(,',@(loop for arg in '(a b c) collect (append (list `cons) (list `',arg) (list arg) 'nil)))
  ``(,',@(loop for arg in '(a b c) collect (list 'cons `(quote ,arg) arg)))
  ``(,',@(loop for arg in '(a b c) collect (list 'cons `(quote ,arg . nil) arg)))
  ``(,',@(loop for arg in '(a b c) collect (list 'cons (append (list `quote) (list arg) 'nil) arg)))
  ``(,',@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg)))
  ``(,',@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg)) . nil)
  `(append (list ',@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg))) 'nil)
  `(list ',@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg)))
  `(list ',@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg)) . nil)
  (append (list `list) (list `',@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg))) 'nil)
  (list 'list `',@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg)))
  (list 'list `(quote ,@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg))))
  (list 'list `(quote ,@(loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg)) . nil))
  (list 'list (append (list `quote) (loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg)) 'nil))
  (list 'list (append (list `quote) (loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg))))
  (list 'list (list* 'quote (loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg))))


When you evaluate that last expression:

  (list 'list (list* 'quote (loop for arg in '(a b c) collect (list 'cons (list 'quote arg) arg))))

you get:

  (LIST (QUOTE (CONS 'A A) (CONS 'B B) (CONS 'C C)))

But that, as Kent pointed out doesn't make any sense since quote
doesn't take three arguments. After that, seems like all bets are off.
However if QUOTE happened to simply return the first argument then
that would evaluate to:

  ((CONS 'A A))

which is close to what you got. (Don't know where that extra backquote
came from though.) So if there's a bug it seems to be that they don't
give a sufficiently clear diagnostic when QUOTE is called with more
than one argument forms. Though whatever fairly recent version of SBCL
I have complains about (quote a b c) so I'm not sure how your macro
works at all.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: james anderson
Subject: Re: @ list splicing bug?
Date: 
Message-ID: <3FC4777C.FD285D7C@setf.de>
Adam Warner wrote:
> 
> Hi all,
> 
> Should the evaluation of:
> ``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))
> 
> Be:
> '((cons 'a a) (cons 'b b) (cons 'c c))
> 
> CMUCL and SBCL return `((cons 'a a)).
> 
> I've distilled this example from one of the macros I have written that has
> returned unexpected results. Before reporting this bug I just want to
> check that my example is portably defined ANSI Common Lisp code and the
> result CMUCL and SBCL returns is not conforming.
> 
> Thanks,
> Adam


Kent M Pitman wrote:
> 
> Adam Warner <······@consulting.net.nz> writes:
> 
> ...
> 
> FWIW, LW 4.2.7 returns
> 
> (QUOTE ((CONS 'A A) (CONS 'B B) (CONS 'C C)))
> 
> but I'm not sure this is really right. ...
> 
> NOTE that ,,@blah is well-defined and tends to mean (conceptually)
>  (mapcar #'comma blah)
> but although ,' usually means simply to suppress an evaluation layer
> it doesn't combine to mean to mean that ,',@ means
>  (mapcar #'identity ,blah)
> ...

it is heartening to know that one can work with a mental model of backquote
behaviour. maybe, someday, i'll get there. in the meantime i offer the
confessions of a backquote wimp. when i manage to mangle a quasi-quoted
expression, i tend to trust the reader to understand backquote better than i do.

? (read-from-string "``(,',@(loop for arg in '(a b c) collect `(cons ',arg ,arg)))")
(LIST* 'LIST (LIST (LIST* 'QUOTE (LOOP FOR ARG IN '(A B C) COLLECT (LIST*
'CONS (LIST* (LIST* 'QUOTE (LIST ARG)) (LIST ARG)))))))
61
? 

which is similar to, but not identical with seibel's analysis, and is amenable
to experimentation, as in

? (LIST* 'LIST (LIST (LIST* 'QUOTE (LOOP FOR ARG IN '(A B C) COLLECT (LIST*
'CONS (LIST* (LIST* 'QUOTE (LIST ARG)) (LIST ARG)))))))
(LIST (QUOTE (CONS 'A A) (CONS 'B B) (CONS 'C C)))
? 

which is not the intended form. on the other hand, after a bit of massaging,

? (LIST 'QUOTE (LOOP FOR ARG IN '(A B C) COLLECT (LIST* 'CONS (LIST* (LIST*
'QUOTE (LIST ARG)) (LIST ARG)))))
'((CONS 'A A) (CONS 'B B) (CONS 'C C))
? 

looks better. working backwards from which

? `(quote ,(LOOP FOR ARG IN '(A B C) COLLECT (LIST* 'CONS (LIST* (LIST* 'QUOTE
(LIST ARG)) (LIST ARG)))))
'((CONS 'A A) (CONS 'B B) (CONS 'C C))
? 

would seem like an expedient formulation.

...