[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: quasiquote implementation
Your implementation, which is very similar to the T and MIT Scheme
quasiquote imeplementations, has the powerful advantage over mine of
conciseness, but it has the serious flaw that it makes the expansion of
nested quasiquote forms visible to the user, thus making it difficult to
write portable code to manipulates such forms. For example, (EQUAL?
'`(A ,B) ``(A ,B)) doesn't hold in your implementation. This seems to
defeat my original aim in suggesting that we standardize the external
syntax of `, which was to allow people to write portable
program-manipulating programs.
Jonathan
Yes, I see what you mean. My goal in making the forms standardized
was to to allow portable code such as an interpreter to make sense
out of what the function "read" returns, and also to provide for the
proper pretty-printing of source programs. I hadn't thought of the
double-quasiquote issue. When I read your first article, I thought
that you wanted
'`(A ,B) = ``(A ,B) => (list (quote a) b)
which is relatively easy (but not desirable, since I didn't want to
reach inside the quote). Instead, I see you want
'`(A ,B) = ``(A ,B) => `(A ,B)
which I can certainly sympathize with. This explains the need for
the "level" variable in your code. For anyone who cares, here is
another (less powerful) version of my code with a level-tracking
argument added. I have tested it only briefly.
(let ((check
(lambda (x)
(unless (and (pair? (cdr x)) (null? (cddr x)))
(ferror (car x) "invalid form ~s" x))))
(quasicons
(lambda (a d)
(if (pair? d)
(if (eq? (car d) 'quote)
(if (and (pair? a) (eq? (car a) 'quote))
`'(,(cadr a) . ,(cadr d))
(if (null? (cadr d))
`(list ,a)
`(list* ,a ,d)))
(if (memq (car d) '(list list*))
`(,(car d) ,a ,@(cdr d))
`(list* ,a ,d)))
`(list* ,a ,d)))))
(define-macro! quasiquote (x)
(recur f ((x x) (n 0))
(cond
((not (pair? x)) `',x)
((eq? (car x) 'quasiquote)
(check x)
(quasicons ''quasiquote (f (cdr x) (1+ n))))
((eq? (car x) 'unquote)
(check x)
(if (zero? n)
(cadr x)
(quasicons ''unquote (f (cdr x) (1- n)))))
((eq? (car x) 'unquote-splice)
(check x)
(if (zero? n)
(ferror 'unquote-splice "invalid context for ,@~s" (cadr x))
(quasicons ''unquote-splice (f (cdr x) (1- n)))))
((and (zero? n) (pair? (car x)) (eq? (caar x) 'unquote-splice))
(check (car x))
(let ((d (f (cdr x) n)))
(if (equal? d '(quote ()))
(cadar x)
`(append ,(cadar x) ,d))))
(else (quasicons (f (car x) n) (f (cdr x) n)))))))
(define-macro! unquote (x)
(ferror 'unquote
"unquote form ,~s not valid outside of quasiquote"
x))
(define-macro! unquote-splice (x)
(ferror 'unquote
"unquote-splice form ,@~s not valid outside of quasiquote"
x))