Subject: Re: Dynamic unquote ( , )?
From: rpw3@rpw3.org (Rob Warnock)
Date: Thu, 09 Feb 2006 19:56:37 -0600
Newsgroups: comp.lang.lisp
Message-ID: <Rt2dnd9FPM5Ib3benZ2dnUVZ_sGdnZ2d@speakeasy.net>
Ulrich Hobelmann  <u.hobelmann@web.de> wrote:
+---------------
| Rob Warnock wrote:
| > In CL perhaps [though even there the situation is a little more
| > complicated than you imply -- it is a stand-in for construction
| > of a *code* sequence that, when evaluated, will perform an explicit
| > list construction], but in Scheme the separation between the reader
| > and the evaluator is complete: *All* the reader does is change the
| > `,,@ markers to QUASIQUOTE, UNQUOTE, and UNQUOTE-SPLICING forms
| > (respectively); it is the evaluator which "executes" the resulting
| > QUASIQUOTE forms. And in particular, even though R5RS warns that:
| 
| I'm wondering: could one create reader-macros to do the conversion as in 
| Scheme, and implement QUASIQUOTE as a macro?  I don't have the time or 
| interest to do so right now, but in theory...
+---------------

In theory, yes. In fact, one could probably "simply" port the
QUASIQUOTE macro from some Scheme implementation into Common Lisp. 

But it might be tricky to preserve all of the original semantics
of the native backquote implementation, especially any performance
optimization tricks they might have done. That is, one of the
*advantages* of conflating the roles of READ & EVAL in backquote
handling in CL is that special cases can be parsed "up front",
when the expression is first read, and not have to wait for when
QUASIQUOTE is expanded later when the optimization might not be
so obvious or available. E.g., when READ sees ",@" it's preseumably
in the middle of reading a list, and it can stop right there and
recursively read the *rest* of the list [pre-empting the list-reading
that's already going on] and convert both the ",@" arg and the tail
of the list after it into a call to some kind of "append", e.g.,
as in CMUCL:

    cmu> (let ((*print-pretty* nil))
	   (princ '`(a ,@(list 'b) c d e f)))
    (LISP::BACKQ-CONS (QUOTE A)
		      (LISP::BACKQ-APPEND (LIST (QUOTE B)) (QUOTE (C D E F))))
    `(A ,@(LIST 'B) C D E F)
    cmu> 

where LISP::BACKQ-CONS & LISP::BACKQ-APPEND are just alternate names
for CONS & APPEND to help the pretty-printer:

    cmu> (LISP::BACKQ-CONS 1 2)

    (1 . 2)
    cmu> (LISP::BACKQ-APPEND '(1 2 3) '(4 5 6))

    (1 2 3 4 5 6)
    cmu> 

Whereas a Scheme-style reader would *have* to return this:

    (quasiquote a (unquote-splicing (list 'b) c d e f))

and then the QUASIQUOTE macro would have to re-parse the list into
equivalent executable code at macro-expansion time [which for an
interpreter might be on every use].

+---------------
| Since macros are (if I'm correct) expanded from outermost to innermost, 
| that would even work, and macros could accept code with UNQUOTEs in it, 
| or manipulate structures like that.
+---------------

Yes, but... It's pretty hairy to get right. This following URL
contains a discussion of some of the subtleties:

    http://www.codecomments.com/message296922.html

BTW, I stumbled across the following naive implementation of
QUASIQUOTE as a syntax-rules macro in the Scheme FAQ. I'm not sure
whether it has any of the bugs mentioned in the previous reference:

    http://community.schemewiki.org/?scheme-faq-language
    ...
    (define-syntax quasiquote
      (syntax-rules (unquote unquote-splicing quasiquote)
	((_ (unquote form))
	 form)
	((_ ((unquote-splicing form) . rest))
	 (append form (quasiquote rest)))
	((_ (quasiquote form) . depth)
	 (list 'quasiquote (quasiquote form #f . depth)))
	((_ (unquote form)  x . depth)
	 (list 'unquote (quasiquote form . depth)))
	((_ (unquote-splicing form) x . depth)
	 (list 'unquote-splicing (quasiquote form . depth)))
	((_ (car . cdr) . depth)
	 (cons (quasiquote car . depth) (quasiquote cdr . depth)))
	((_ #(elt ...) . depth)
	 (list->vector (quasiquote (elt ...) . depth)))
	((_ atom . depth)
	 'atom)))

    The expansion is not "optimal" - it does not exploit Scheme's
    abilitity to represent constant lists and vectors as literals.
    It is possible to write a macro that does that, but it is rather
    long and hence not included here.

+---------------
| Finally, the QUASIQUOTE macro would expand its arguments accordingly 
| (while looking for the , and ,@).
+---------------

You meant "while looking for any UNQUOTEs, UNQUOTE-SPLICINGs, or
additional QUASIQUOTEs", I hope, since all of the ` , ,@ characters
would be long gone before the QUASIQUOTE macro runs.


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607