LET OVER LAMBDA Reading
昨日の続きでバッククォートでネストされているマクロを追ってみる。
macroexpand-1がマクロを1回分だけ展開する関数なのでこれを使ってみてみよう。
(macroexpand-1 '(defmacro! square (o!x) `(* ,g!x ,g!x)))
このようにmacroexpand-1に展開させたいマクロS式をクォートして渡す。
(DEFMACRO/G! SQUARE (O!X) (LIST 'LET (MAPCAR #'LIST (LIST G!X) (LIST O!X)) (PROGN `(* ,G!X ,G!X))))
展開するとこのようになっていて、これをバッククォートを使って書き換えると
(defmacro/g! square (O!X) `(let ,(mapcar #'list (list G!X) (list O!X)) ,(progn `(* ,G!X ,G!X))))
のようになる。こいつをさらにmacroexpand-1に渡してあげる
(macroexpand-1 '(defmacro/g! square (O!X) `(let ,(mapcar #'list (list G!X) (list O!X)) ,(progn `(* ,G!X ,G!X)))))
展開結果は
(DEFMACRO SQUARE (O!X) (LET ((G!X (GENSYM "X"))) `(LET ,(MAPCAR #'LIST (LIST G!X) (LIST O!X)) ,(PROGN `(* ,G!X ,G!X)))))
このS式でdefmacroにとってのbodyは
`(LET ,(MAPCAR #'LIST (LIST G!X) (LIST O!X)) ,(PROGN `(* ,G!X ,G!X)))
なので展開後は
(LET ((#:X8704 O!X)) (* ,G!X ,G!X))
のようになる。PROGNを包んでいた括弧はアンクォートされたいたので展開時に評価されてなくなり、中のバッククォートされたS式は評価されずにそのまま残る。
だから、昨日言っていた,@なんたらのくだりは解釈の間違いで、バッククォートはそのまま残った形でdefmacroに渡る。