関数内のマクロが展開されるのはどの時点

なんか日本語不自由なタイトルだ。
前回 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 "

*1:コンパイル済みな「関数を生成する関数」で作ると、生成された関数もコンパイルされるので注意