[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Scheme-reports] What happened to (UNQUOTE <expression> ...)

On Sun, 24 Apr 2011, Alex Shinn wrote:

> On Sun, Apr 24, 2011 at 9:04 AM, Andre van Tonder <andre@x> wrote:
>> and (unquote-splicing <expression> ...)?
>> In other words, more than one argument to UNQUOTE(-SPLICING).
>> These were added in R6RS to fix some well-known shortcomings of quasiquote.
>> The issue and the R6RS solution had been known for a long time and were
>> discussed by many authors for many years before being adopted.
>> I for one liked the change and probably have code that depends on it.
> It looks reasonable to me, but could you point us
> to the discussions or rationales?
> Specifically, how is (unquote-splicing a b c) different from
> ,@a ,@b ,@c ?

I think the issue is a little more complex that this, it has to do with the 
fact that nested unquote-splicing was accidentally broken in Scheme, but since I 
don't remember the details offhand, let me quote Al* Petrofsky on this issue. 
By the way, the solution he suggests was not the one adopted for R6RS - instead 
I think R6RS adopted the Chez fix he mentions, probably becasue it is more 
backwards compatible and there was more experience with it.

Anyway, here is Petrofsky's discussion:

From: Alf Petrofsky <alf@x>
Newsgroups: comp.lang.scheme
Subject: Re: getting a list into a macro
Date: 27 Nov 2001 16:39:42 -0800
Message-ID: <87k7wbbuep.fsf@radish.petrofsky.org>

ds26@x (Dorai Sitaram) writes:

>(define-macro create-class
> (lambda (superclass slots . methods)
> `(create-class-proc
> ,superclass
> (list ,@(map (lambda (slot) `',slot) slots))
> (list ,@(map (lambda (method) `',(car method)) methods))
> (vector ,@(map (lambda (method) `,(cadr method)) methods)))))

This quasiquotation seems overly complicated to me. Is there any
reason you don't write it more simply, like this:

(define-macro create-class
(lambda (superclass slots . methods)
',(map car methods)
(vector ,@(map cadr methods)))))


P.S. The vector should be further abbreviable to `#(,,@(map cadr
methods)), but unfortunately the r5rs specification of quasiquote is
broken with respect to nested unquote-splicing. Chez scheme supports
such quasiquotations as a compatible extension to the r5rs semantics.

P.P.S. Common Lisp specifies nested quasiquotation in a way that
makes ,,@expr useful. When nested quasiquote was added to scheme in
r3rs, it was intended to be compatible with lisp. Because the method
of specification was turned inside out from the lisp method, it was
not noticed that nested quasiquotation had been broken. One way to
make scheme compatible with common lisp would be to add the following
to r5rs:

When a comma at-sign and the expression that follows it are being
replaced by the elements of the list that resulted from the
expression's evaluation, any sequence of commas and comma at-signs
that immediately preceeded the comma at-sign is also removed and is
added to the front of each of the replacements.

(let ((x '(a b c))) ``(,,x ,@,x ,,@x ,@,@x))
=> `(,(a b c) ,@(a b c) ,a ,b ,c ,@a ,@b ,@c)

``(,,@'() ,@,@(list))
=> `()

`````(a ,(b c ,@,,@,@(list a b c)))
=> ````(a ,(b c ,@,,@a ,@,,@b ,@,,@c))

When I discovered this problem, I couldn't find anything that had been
written about it, so I started to prepare a long-winded missive and a
srfi. The work withered after I discovered the chez scheme fix and
couldn't decide whether I preferred their approach (uglier, but more
backwards-compatible) or mine. This postscript, and the excuse for an
article that preceeded it, are an attempt to at least get something
about the subject into google.

Here's a simple implementation of the above specification:

;; As an undocumented "feature" this takes optional extra arguments,
;; which must all be #f. One level of unquotation is ignored per
;; extra argument supplied.
(define-syntax quasiquote
(syntax-rules (unquote unquote-splicing quasiquote)
((_ ,x ) x)
((_ (,@x . y) ) (append x `y))
((_ `x . d) (list 'quasiquote (quasiquote x #f . d)))
((_ ,x #f . d) (list 'unquote (quasiquote x . d)))
((_ (,x . y) #f . d) (append (map (lambda (z) (list 'unquote z))
(quasiquote (x) . d))
(quasiquote y #f . d)))
((_ (,@x . y) #f . d) (append (map (lambda (z) (list 'unquote-splicing z))
(quasiquote (x) . d))
(quasiquote y #f . d)))
((_ (x . y) . d) (cons (quasiquote x . d) (quasiquote y . d)))
((_ #(x ...) . d) (list->vector (quasiquote (x ...) . d)))
((_ x . d) 'x)))

Scheme-reports mailing list