| In Common Lisp: $ clisp
[1]> (setf xs '(x1 x2) ys '(y1 y2) x1 'a x2 'b y1 'c y2 'd)
D
[2]> ``(list ,,@(mapcar #'(lambda (x y) ``(,,x ,,y)) xs ys))
(LIST 'LIST (LIST X1 Y1) (LIST X2 Y2))
[3]> (eval ``(list ,,@(mapcar #'(lambda (x y) ``(,,x ,,y)) xs ys)))
(LIST (A C) (B D))
But in Arc: $ cd arc3/
$ mzscheme -v
Welcome to MzScheme version 360, Copyright (c) 2004-2006 PLT Scheme Inc.
$ rlwrap mzscheme -m -f as.scm
Use (quit) to quit, (tl) to return here after an interrupt.
arc> (= xs '(x1 x2) ys '(y1 y2) x1 'a x2 'b y1 'c y2 'd)
d
arc> (eval ``(list ,,@(map (fn (x y) ``(,,x ,,y)) xs ys)))
(list (a c))
Odd. The culprit? arc> ``(list ,,@(map (fn (x y) ``(,,x ,,y)) xs ys))
(quasiquote
(list
(unquote (quasiquote ((unquote x1) (unquote y1)))
(quasiquote ((unquote x2) (unquote y2))))))
Or, more simply arc> `(unquote ''x ''y)
(quote x)
So, Arc's unquote only expects a single argument, ditching the remaining ones silently, whereas mzscheme makes this rather explicit: $ mzscheme
Welcome to MzScheme version 360, Copyright (c) 2004-2006 PLT Scheme Inc.
> `(unquote ''x ''y)
stdin::0: unquote: expects exactly one expression at: (unquote (quote (quote
x)) (quote (quote y))) in: (quasiquote (unquote (quote (quote x)) (quote
(quote y))))
=== context ===
qq
repl-loop
Is there any compelling reason for unquote to only take one argument? Common Lisp seems to simply unquote every argument, so that forms like ,,@(...) will work. Though rare, nested quasiquotes do appear in actual code. For instance, I found this case by porting Peter Siebel's Common Lisp version of 'once-only to Arc: (defmacro once-only ((&rest names) &body body)
(let ((gensyms (loop for n in names collect (gensym))))
`(let (,@(loop for g in gensyms collect `(,g (gensym))))
`(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n)))
,(let (,@(loop for n in names for g in gensyms collect `(,n ,g)))
,@body)))))
I got as far as (mac once-only (names . body)
(let gensyms (map1 [uniq] names)
`(with ,(mappend (fn (g) `(,g (uniq))) gensyms)
`(with ;?
,(with ,(mappend (fn (n g) `(,n ,g)) names gensyms)
,@body)))))
before discovering this little property of unquote. Of course, using 'mappend here wouldn't work so well, since it'll churn out some fun results with the nested quasiquotes: arc> (mappend (fn (g n) ``(,,g ,,n)) '(g1 g2 g3) '(n1 n2 n3))
(quasiquote ((unquote g1) (unquote n1))
quasiquote
((unquote g2) (unquote n2))
quasiquote
((unquote g3) (unquote n3)))
My next inclination would be to try using a 'let to destructure the gensyms against the names, but I'm burnt out at the moment. Anyone have any suggestions on how to finish this macro?As for unquote only taking one argument: Is it a bug? A feature? It seems like Arc should at least report an error, as mzscheme does (in version 360, anyways). |