関数内のマクロが展開されるのはどの時点
なんか日本語不自由なタイトルだ。
前回 lisp-unit.lisp のこと書いた中で、macro を含む関数を作るとその macro は展開されたカタチで保存される、みたいなことを書いたのだけど、*scratch* で色々やってたらそーでもない場合もあるみたいだったので調べてみた。
先にまとめ:
macro 呼び出しを含む関数内の macro 呼び出しが展開されるのは
- 関数を呼び出したとき
- 関数をコンパイルしたとき
のどっちか。
なので関数を作っただけでは macro は展開されない*1。
調べてみたログ
;; hoge は未定義 (hoge 1 2 3) >> 関数が定義されていません: hoge ;; hoge を含む関数を作ってみる (defun with-hoge () (hoge 1 2 3)) => with-hoge (with-hoge) >> 関数が定義されていません: hoge ;; コンパイル済みのも用意しておく (defun with-hoge* () (hoge 1 2 3)) => with-hoge* (compile 'with-hoge*) => with-hoge* (with-hoge*) >> 関数が定義されていません: hoge ;; hoge を定義; ver.1 (defmacro hoge (&rest args) `(format nil "~{~S ~}" ',args)) => hoge ;; コンパイルしてない方はちゃんと実行できた (with-hoge) => "1 2 3 " ;; コンパイルしてあると不可思議なエラーが (with-hoge*) >> 不正な関数です: hoge ;; コンパイルしなおしてみる ;; コンパイル済みの関数をコンパイルってどーなるんだ? (compile 'with-hoge*) => with-hoge* ;; 変わらなかった (with-hoge*) >> 不正な関数です: hoge ;; 関数定義からやりなおし。ま、これは動くわな (compile (defun with-hoge* () (hoge 1 2 3))) => with-hoge* (with-hoge*) => "1 2 3 " ;; hoge を再定義すると・・・ (defmacro hoge (&rest args) `(+ ,@args)) => hoge ;; 未 compiled な方はちゃんと新しい hoge になった (with-hoge) => 6 ;; compiled な方は古い定義のままだった (with-hoge*) => "1 2 3 "