#251 Wrong result with double splice ,@,@

Stable_release
open
nobody
None
1
2014-08-16
2013-01-14
Anonymous
No
``(foo ,@,@nil)  ;=> (LIST* 'FOO)

Discussion


  • Anonymous
    2013-01-15

    CCL has a similar bug report (http://trac.clozure.com/ccl/ticket/6).

    Conceptually what should happen:

    ``(f ,@,@(list '(list :x 1) '(list :y 2)))
    ;; =>
    `(F ,@(LIST :X 1) ,@(LIST :Y 2))
    ;; =>
    (F :X 1 :Y 2)
    

    What happens in ECL and CCL:

    ``(f ,@,@(list '(list :x 1) '(list :y 2)))
    ;; =>
    (LIST* 'F (LIST :X 1) (LIST :Y 2))
    ;; =>
    (F (:X 1) :Y 2)
    
     
  • I am not sure that the ,@,@ is conceptually correct. The outer ,@ has a list that encloses it, but the inner ,@ does not. I would have expected that ,@(,@) is what should be written and indeed this works

    > ``(f ,@(,@(list '(list :x 1) '(list :y 2))))
    
    (LIST* 'F ((LIST :X 1) (LIST :Y 2)))
    
     
    Last edit: Juan Jose Garcia Ripoll 2013-01-15

  • Anonymous
    2013-01-15

    Going back to the CCL bug report, the goal is to splice

    (defparameter *c* `((list :x 1) (list :y 2)))
    

    We want to evaluate something twice to get

    (F :X 1 :Y 2)
    

    The non-CCL/non-ECL way to do this is with

    (eval ``(f ,@,@*c*)) ;=> (F :X 1 :Y 2)
    

    How do we do it on ECL? You seem to be suggesting

    (eval ``(f ,@(,@*c*)))
    

    but that is an error on any implementation, ECL included.

    (eval ``(f ,@(,@(list '(list :x 1) '(list :y 2)))))
    

    is also an error.

     

  • Anonymous
    2013-01-15

    I guess this is it?

    (eval ``(f ,@(append ,@*c*))) ;=> (F :X 1 :Y 2)
    

    There's something unsettling about combining append and splice.

     

  • Anonymous
    2013-01-16

    Please understand that this all is not about how it is to be done in ECL but it is about how it is to be done in portable Common Lisp. The fact that what you intend to do works on certain implementations does not mean that it is contemplated by the standard.

    If you read the specification, you can splice ONE FORM http://www.lispworks.com/documentation/HyperSpec/Body/02_df.htm The specification says it clearly: If a comma is immediately followed by an at-sign, then THE FORM following the at-sign is evaluated to produce a list of objects. These objects are then ``spliced'' into place in the template.

    What the original code intended was to apply ,@ to a list of forms and this is nowhere to be seen in that text.

    So indeed the solution is what you showed: pass the inner ,@ a list of objects to unquote as in the (append ...) solution.

     

  • Anonymous
    2013-01-23

    I was responding to your initial reply, which didn't make sense to me: "The outer ,@ has a list that encloses it, but the inner ,@ does not." You mean the other way around, right? And the example you gave did not generate the intended code.

    You are focusing on "the form", but the most we can say is that it's ambiguous. After *c* is spliced the first time, and before it is spliced the second time, it only exists as some internal data structure. There isn't an output for the result; there isn't any formally defined lisp code to which it corresponds, so we can't talk about forms. Otherwise we are forced to say that all the non-ECL/non-CCL implementations are wrong for representing it internally as "ONE FORM".

    Micro-parsing "the form" is not a compelling argument to me, while the overall intention behind splicing is compelling. The purpose of splicing is to free us from APPEND. Splicing functionality should be complete in that it covers all uses, without any side cases where we must resort to APPEND.

    I suppose there's almost no chance that CCL or ECL will change, so I'll consider the issue moot. I concede there is no technical requirement to handle ,@,@ in a particular way, however I argue that one way is in accord with the "spirit of the splicing" while the other isn't.

     

  • Anonymous
    2013-01-23

    I concede that the example I generated did not produce your intended code, but this is because I did not even have an idea of what you wanted to do or how you interpreted the ,@,@

    You say that "After c is spliced the first time, and before it is spliced the second time, it only exists as some internal data structure." and I argue that this is NOT the case. The behaviour of backquote is defined in terms of what forms they produce and the reader in ECL applies strictly the specification, by which there is NO NEED to create any intermediate structure at all: ,@ is recognized inside a list and produces a an append form, "," does something similar, etc. The result is that there is no need to spill out backquote/quote/splice symbols unlike what SBCL does

    [SBCL] * ``(a ,@,@'((list a)))
    
    `(A ,@(LIST A))
    
    [ECL] > ``(a ,@,@'((list a)))
    
    (LIST* 'A (LIST A))
    

    I personally prefer the last approach, as it produces code that is directly Common Lisp and not some set of forms that still have to be macroexpanded.

    It is because of this difference that your expected behavior does not work at all. When the reader sees ``(... ,@,@(list a b c) ...) it tries to generate the form associated to ,@ but it lacks completely a context, since that ,@ does not form part of any list at all.

    Let me insist on this:

    1) In the ANSI specification backquote syntax is defined with a single level of equalities, without any recursive behavior where inner behavior depends on external conditions.

    2) Your expected behavior is that ,@ acts recursively on the elements produced by some ,@. This requires some deeper definition than the one provided by ANSI.

    3) Moreover, this last definition is contradictory with the one in ANSI, which states that the elements of ,@ are spliced or spilled in place in the form. If I relax this definition ignoring the fact that the ,@ is not inside any list I should get

    ``(... ,@,@(list a b c) ...) -> `(... ,@a b c ...) [1]
    

    while your requirement is

     ``(... ,@,@(list a b c) ...) -> `(... ,@a ,@b ,@c ...)
    

    Note that [1] could be somebody's own interpretation of what is closer to the spirit and still not being covered by the current specification.

    We could now discuss about the spirit which is right now your interpretation, but without some deeper discussion with other parties involved right now there is the situation of touching an implementation of the reader which is conformant and not broken and risking to break it just to satisfy this single instance.

     

  • Anonymous
    2013-01-23

    I am not sure why you responded since I ended with, "I concede that there is no technical requirement to handle ,@,@ in a particular way".

    I don't know how to assure you that I understand the issue at hand. I thought my last comment would have made that clear. Your additional explanations further confirm that we are talking about the same thing, but are not otherwise revelatory.

    You seem to take offense to my belief that the "spirit of splicing" is to free us from having to use APPEND. If that is all we're really talking about at this point, can't we just disagree about that?

    However your last response seems to go further, to wit,

    Moreover, this last definition is contradictory with the one in ANSI, which states that the elements of ,@ are spliced or spilled in place in the form.

    But the elements haven't been spilled yet. The situation is ambiguous, as I explained previously. ECL and CCL took one path, the other lisps took another path. But you say contradictory, not ambiguous -- are you now suggesting that SBCL, CLISP, ABCL, Lispworks, and Allegro violate the ANSI spec in this regard?

     
  • ,@,@ is well defined. See the Alan Bawden article about quasiquotation in lisp.

    fare-quasiquote has a portable implementation of backquote that handles ,@ correctly (it's hard: the first time around, I didn't do it well). You can take code from it, if that helps.

     


Anonymous


Cancel   Add attachments