自家製quasiquote

Lispのunquoteしか対応していなかったquasiquoteをunquote-splicingにも対応させてみた。
and,or,cond等の基本マクロの定義にもquasiquoteを使えるように、quasiquote自体の定義にはそれらは使わずに以下で代用。
(and x y) → (if x y #f)で代用。
(or x y) → (if x #t y)で代用。
(cond ...) → ifの入れ子で代用。

(define-macro (quasiquote x)
  (if (not (pair? x)) (list 'quote x)
    (if (if (eq? (car x) 'unquote) #t (eq? (car x) 'unquote-splicing)) (cadr x)
      (list (if (if (pair? (car x)) (eq? (car (car x)) 'unquote-splicing) #f) 'append 'cons)
            (list 'quasiquote (car x))
            (list 'quasiquote (cdr x))))))

作ってみてわかったんだけど、`(a b ,@x)と書いていた部分は、`(a b . ,x)と書いても動くことに気がついた。
これって、,xの実体は(unquote x)というリストだから、全体は(quasiquote (a b unquote x))となっているわけだ。
アルゴリズム的にはわかっていても、見た目的にunquoteが先頭要素じゃなくリスト中に埋もれているのに動くのっておもしろい。

repl> `(a b . ,(list 1 2))
(a b 1 2)

http://kar.s206.xrea.com/lisp/?e=%60(a%20b%20.%20%2C(list%201%202))

repl> '`(a b . ,(list 1 2))
(quasiquote (a b unquote (list 1 2)))

http://kar.s206.xrea.com/lisp/?e=%27%60(a%20b%20.%20%2C(list%201%202))

Gaucheでも同じ動作だった。

gosh> `(a b . ,(list 1 2))
(a b 1 2)
gosh> '`(a b . ,(list 1 2))
`(a b unquote (list 1 2))

うわ、本当は入れ子も対応しないといけないのか。

R6RS:翻訳:R6RS:11.17 Quasiquotation
quasiquote フォームは入れ子にすることができる。置き換えは一番外側の quasiquote と同じ入れ子レベルの部分に現れた unquote された要素にだけ行われる。入れ子レベルはそれぞれ次の quasiquote で 1 増加し、 unquote の内側で 1 減少する。

`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f) 
                ⇒  (a `(b ,(+ 1 2) ,(foo 4 d) e) f)
http://practical-scheme.net/wiliki/wiliki.cgi?R6RS%3A%E7%BF%BB%E8%A8%B3%3AR6RS%3A11.17%20Quasiquotation