ウォンツテック

そでやまのーと

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に渡る。