From: Kaz Kylheku
Subject: nested backquote: interpretation of ,,@ and ,@,@.
Date: 
Message-ID: <cf333042.0303211635.57247581@posting.google.com>
In a nested backquote, does the syntax ,,@form and ,@,@form have any
meaning? Should an error be signaled? Is the behavior undefined?

A naive expectation might be that in evaluating ``(,@,@(list ''(1 2) 3
4)), the value of (list '(1 2) 3 4) be naively spliced into the form
to effectively produce `(,@'(1 2) 3 4) which then produces (1 2 3 4)
when evaluated again.In other words, the left splice refers only to
the first element of the result of the right splice, as if the
splicing were done by naive text replacement of ,@ for the list
contents with parentheses removed. ;)

The problem with that interpretation is that if we consider an
implemenation which translates the read-syntax to a Scheme-like
quasiquote macro, we get the syntax:

   (quasiquote
     (quasiquote 
       (unquote-splicing (unquote-splicing (list ''(1 2) 3 4)))))

in which the splicing unquotes are nested. Thus the straightforward
backquote expander wants to treat the right splicing unquote as being
entirely subordinate to the left.

I'm asking this because in the CLISP implementation notes, the ,@ and
,@,@ are not supported, giving rise to the implication that this is
some kind of defficiency. Since I have rewritten the backquote support
from scratch, I want to resolve every outstanding issue.

From: Timothy Moore
Subject: Re: nested backquote: interpretation of ,,@ and ,@,@.
Date: 
Message-ID: <b5gq85$uuu$0@216.39.145.192>
···@ashi.footprints.net (Kaz Kylheku) writes:

> In a nested backquote, does the syntax ,,@form and ,@,@form have any
> meaning? Should an error be signaled? Is the behavior undefined?
> 
,,@forms is well defined. Briefly, forms is spliced into the
surrounding list; in the second evaluation, those forms are
evaluated.  Here's an example of ,,@ from McCLIM:

(defmacro defgeneric* (fun-name lambda-list &body options)
  "Defines a SETF* generic function.  FUN-NAME is a SETF function
name.  The last argument is the single argument to the function in a
SETF place form; the other arguments are values collected from the
SETF new value form."
  (unless (setf-name-p fun-name)
    (error "~S is not a valid name for a SETF* generic function." fun-name))
  (let ((setf-name (cadr fun-name))
	(args (butlast lambda-list))
	(place (car (last lambda-list))))
    `(progn
       (defsetf ,setf-name (,place) ,args
	 `(funcall #',',fun-name ,,@args ,,place))
       (defgeneric ,fun-name ,lambda-list ,@options))))

> I'm asking this because in the CLISP implementation notes, the ,@ and
> ,@,@ are not supported, giving rise to the implication that this is
> some kind of defficiency. Since I have rewritten the backquote support
> from scratch, I want to resolve every outstanding issue.

It is a deficiency.

Tim
From: Kaz Kylheku
Subject: Re: nested backquote: interpretation of ,,@ and ,@,@.
Date: 
Message-ID: <cf333042.0303232110.334ebe84@posting.google.com>
Timothy Moore <·····@bricoworks.com> wrote in message news:<············@216.39.145.192>...
> ···@ashi.footprints.net (Kaz Kylheku) writes:
> 
> > In a nested backquote, does the syntax ,,@form and ,@,@form have any
> > meaning? Should an error be signaled? Is the behavior undefined?
> > 
> ,,@forms is well defined. Briefly, forms is spliced into the
> surrounding list; in the second evaluation, those forms are
> evaluated.  Here's an example of ,,@ from McCLIM:

Do you mean that a kind of algebraic distributive law applies, right?
So that in other words:

  (,@LIST) 

is like 

  (LIST ,(FIRST LIST) ,(SECOND LIST) ... ,(NTH N LIST)) 

If so, ka-ching! This is what my implementation does. For example:

  (macroexpand-1 '``(,,@(list '(+ 1 2) '(+ 2 3))))

  ==> `(LIST ,@(LIST '(+ 1 2) '(+ 2 3))) ;

  (macroexpand '``(,,@(list '(+ 1 2) '(+ 2 3))))

  ==> '(LIST (+ 1 2) (+ 2 3))

  ``(,,@(list '(+ 1 2) '(+ 2 3))) 

  ==> (LIST (+ 1 2) (+ 2 3))

  second evaluation

  ==> (3 5)

This is exactly what would happen if we manually unspliced our list:

  ``(,(+ 1 2) ,(+ 2 3))

  ==> (LIST (+ 1 2) (+ 2 3))

Thus the inner ,@ basically evaluates the list, and then the outer
unquote is algebraically distributed into these.

This behavior arose simply from implementing the CLHS specification
very carefully.

> (defmacro defgeneric* (fun-name lambda-list &body options)
>   "Defines a SETF* generic function.  FUN-NAME is a SETF function
> name.  The last argument is the single argument to the function in a
> SETF place form; the other arguments are values collected from the
> SETF new value form."
>   (unless (setf-name-p fun-name)
>     (error "~S is not a valid name for a SETF* generic function." fun-name))
>   (let ((setf-name (cadr fun-name))
> 	(args (butlast lambda-list))
> 	(place (car (last lambda-list))))
>     `(progn
>        (defsetf ,setf-name (,place) ,args
> 	 `(funcall #',',fun-name ,,@args ,,place))
>        (defgeneric ,fun-name ,lambda-list ,@options))))

Thanks for this example use.
From: Kaz Kylheku
Subject: Re: nested backquote: interpretation of ,,@ and ,@,@.
Date: 
Message-ID: <cf333042.0303241043.25d9633@posting.google.com>
Timothy Moore <·····@bricoworks.com> wrote in message news:<············@216.39.145.192>...
> ···@ashi.footprints.net (Kaz Kylheku) writes:
> 
> > In a nested backquote, does the syntax ,,@form and ,@,@form have any
> > meaning? Should an error be signaled? Is the behavior undefined?
> > 
> ,,@forms is well defined. Briefly, forms is spliced into the
> surrounding list; in the second evaluation, those forms are
> evaluated.

I now have this interpretation of ,@,@. It has a distributive law like
,,@; the forms are spliced into the surrounding list. In the second
evaluation, those forms are evaluated, and their values are also
spliced into the surrounding list.
 
Therefore, two evaluations of the expansion of:

  ``(1 ,,@'((list 2 3) (list 4 5)) 6)

result in

   (1 (2 3) (4 5))  ;; as if ``(1 ,(list 2 3) ,(list 4 5) 6)

and if we change that to:

  ``(1 ,@,@'((list 2 3) (list 4 5)) 6)

the second-level results are spliced:

   (1 2 3 4 5)   ;; as if ``(1 ,@(list 2 3) ,@(list 4 5) 6)

LispWorks has this behavior; Corman ditto.

The ,,@ works fine in my implementation, and it *almost* handles ,@,@.
That is, it works with bq optimization off, but when optimization is
enabled, in some cases it performs an illegal reduction of `(APPEND
,@FORM) to `,@FORM. The optimizer doesn't understand that the the
``stray'' ,@ form that remains in the output has special semantics
that must be rpeserved for the next expansion round. Once I smooth
this over, I think it will work. So we are on the home stretch.
From: Alexey Dejneka
Subject: Re: nested backquote: interpretation of ,,@ and ,@,@.
Date: 
Message-ID: <m38yv8oy86.fsf@comail.ru>
Hello,

···@ashi.footprints.net (Kaz Kylheku) writes:

> In a nested backquote, does the syntax ,,@form and ,@,@form have any
> meaning? Should an error be signaled? Is the behavior undefined?
> 
> A naive expectation might be that in evaluating ``(,@,@(list ''(1 2) 3
> 4)), the value of (list '(1 2) 3 4) be naively spliced into the form
> to effectively produce `(,@'(1 2) 3 4) which then produces (1 2 3 4)
> when evaluated again.In other words, the left splice refers only to
> the first element of the result of the right splice, as if the
> splicing were done by naive text replacement of ,@ for the list
> contents with parentheses removed. ;)

Naive reading of CLHS 2.4.6:

  ``(,@,@(list ''(1 2) 3 4)) ==
  `(append [,@,@(list ''(1 2) 3 4)] 'nil) ==
  `(append ,@(list ''(1 2) 3 4) 'nil)

First evaluation:

  (append ''(1 2) 3 4 'nil)

Second evaluation:

  type error


CLtL2, appendix C contains an implementation of backquote and gives a
lot of examples, including embedded bqs.

-- 
Regards,
Alexey Dejneka

"<Zhivago> mutants tend to turn evil after a while, and go around
eating people's brains." -- #lisp
From: Kaz Kylheku
Subject: Re: nested backquote: interpretation of ,,@ and ,@,@.
Date: 
Message-ID: <cf333042.0303232053.2a31b1c8@posting.google.com>
Alexey Dejneka <········@comail.ru> wrote in message news:<··············@comail.ru>...
> Hello,
> 
> ···@ashi.footprints.net (Kaz Kylheku) writes:
> 
> > In a nested backquote, does the syntax ,,@form and ,@,@form have any
> > meaning? Should an error be signaled? Is the behavior undefined?
> > 
> > A naive expectation might be that in evaluating ``(,@,@(list ''(1 2) 3
> > 4)), the value of (list '(1 2) 3 4) be naively spliced into the form
> > to effectively produce `(,@'(1 2) 3 4) which then produces (1 2 3 4)
> > when evaluated again.In other words, the left splice refers only to
> > the first element of the result of the right splice, as if the
> > splicing were done by naive text replacement of ,@ for the list
> > contents with parentheses removed. ;)
> 
> Naive reading of CLHS 2.4.6:
> 
>   ``(,@,@(list ''(1 2) 3 4)) ==
>   `(append [,@,@(list ''(1 2) 3 4)] 'nil) ==
>   `(append ,@(list ''(1 2) 3 4) 'nil)

In fact, my implementation, at least when optimization is disabled,
follows the CLHS quite closely:

  [1]> (setf system::*backquote-optimize* nil)

  ** - Continuable Error
  SETQ(SYSTEM::*BACKQUOTE-OPTIMIZE*): #<PACKAGE SYSTEM> is locked
  If you continue (by typing 'continue'): Ignore the lock and proceed
  1. Break [2]> continue
  NIL
  [3]> (macroexpand-1 '``(,@,@(list ''(1 2) 3 4)))
  `(APPEND ,@(LIST ''(1 2) 3 4)) ;
  T
  [4]> (macroexpand '``(,@,@(list ''(1 2) 3 4)))
  (APPEND (LIST 'APPEND) (LIST ''(1 2) 3 4)) ;
  T 
  [5]> ``(,@,@(list ''(1 2) 3 4))) 
  (APPEND '(1 2) 3 4)

Because I implemented backquote as a macro, it will be expanded
recursively; the first expansion of (SYSTEM::BACKQUOTE ...) results in
another (SYSTEM::BACKQUOTE ...) form which is then reduced again. As
you can see, I had to use MACROEXPAND-1 to capture the first round by
itself, and it matches what you have, except for the lone 'NIL at the
end; I took liberty to deviate from the spec slightly there, and not
reduce the proper list cases to (x1 .. xn . nil).

> First evaluation:
> 
>   (append ''(1 2) 3 4 'nil)

You mean (append '(1 2) ...), right? See above working code! ;)

> Second evaluation:
> 
>   type error

Right.

By the way, if we leave optimization on, here is what happens:

  [1]>  (macroexpand-1 '``(,@,@(list ''(1 2) 3 4)))
  `,@(LIST ''(1 2) 3 4) ;
  T
  [2]>  (macroexpand '``(,@,@(list ''(1 2) 3 4)))

  *** - The syntax `,@form is undefined behavior.

The APPEND is optimized away in the first expansion round, which
promotes the second ,@ to a non-list context. And so the error occurs
at expansion time, prior to even the first evaluation, rather than on
the second evaluation.