LET OVER LAMBDA Reading
マクロを定義するマクロを定義するには,しばしば入れ子になった逆クォートが必要になる.逆クォートの入れ子は理解し辛いことで悪評が高い.よく使われる形にはいつか慣れるだろうが,逆クォートの付いた任意の式を見て,どのように展開されるかを言えるようになるとは思うべきではない.そうなるのはLispの欠陥ではなく,ましてや表記の欠陥でもない.込み入った積分の数式を見て値が何か知ることができないのと同じことだ.困難は問題の中にあり,表記の中にあるのではない.
http://www.komaba.utmc.or.jp/~flatline/onlispjhtml/macroDefiningMacros.html
LOL リスト2.6 & リスト2.8
(defmacro defmacro/g! (name args &rest body) (let ((syms (remove-duplicates (remove-if-not #'g!-symbol-p (flatten body))))) `(defmacro ,name ,args (let ,(mapcar (lambda (s) `(,s (gensyms ,(subseq (symbol-name s) 2)))) syms) ,@body)))) (defmacro defmacro! (name args &rest body) (let* ((os (remove-if-not #'o!-symbol-p args)) (gs (mapcar #'o!-symbol-to-g!-symbol os))) `(defmacro/g! ,name ,args `(let ,(mapcar #'list (list ,@gs) (list ,@os)) ,(progn ,@body)))))
Paulはこんな感じのマクロを理解するのは積分を解くのと同じって事を言いたいのか?
言いたい事はなんとなく分かるが積分の方が100倍楽だと思うね僕は。
バッククォートはアンクォート(,)が無ければただのクォート。つまり評価しないって識別子と考える。
内側のバッククォートは評価されないと考えると最初のdefmacro!の展開は
(defmacro/g! name args `(let ,(mapcar #'list (list '(gs1 gs2)) (list '(os1 os2))) ,(progn body)))
みたいになる(o!-symbol-pを満たすargsが2個の場合と仮定) たぶん。。
defmacro/g!に渡されるbody部分が
`(let ,(mapcar #'list (list '(gs1 gs2)) (list '(os1 os2))) ,(progn body))
でこれをdefmacro/g!に適用するんだけどgs1とgs2がgensymで生成された変数に変換される。
でもbodyのところにバッククォートが残るな。。
わからない寝よう
いや、まて
,@bodyの,@って「継ぎ合わせアンクォート」って読み方で別に特殊な記号じゃない。ただのアンクォートだ。
って事はdefmacro/g!からの展開した時のbodyは
(let ,(mapcar #'list (list '(gs1 gs2)) (list '(os1 os2))) ,(progn body))
が正解だね、たぶん。
これからdefmacro/g!全体
(defmacro defmacro/g! (name args &rest body) (let ((syms (remove-duplicates (remove-if-not #'g!-symbol-p (flatten body))))) `(defmacro ,name ,args (let ,(mapcar (lambda (s) `(,s (gensyms ,(subseq (symbol-name s) 2)))) syms) ,@body))))
の,@bodyにさっきのbodyが渡る。
って事は展開すると
(defmacro name args (let ((#:X1633 os1) (#:X1634 os2)) (progn body)))
のようになる。ふむ、これは正しい。
最後の方の解釈が間違えてる。 今夜再思考しよう。