コンパイルしていると思ったらいつのまにか定義していた
木曜日, 9月 1st, 2011何を言ってるのか わからねーと思うが、
取り敢えず下の2つのファイルを御覧ください。
;;; a.lisp (defmacro foo (x) `(list ,x ,x))
;;; b.lisp (defun bar () (foo (+ 1 2))) ; 上記マクロを使いたい
処理系を起動した直後に、
これらのファイルを次のようにコンパイルする場合を考えます。
(compile-file "a.lisp") (compile-file "b.lisp")
さて、この行為は実は問題があります。
a.lispをコンパイルしただけでは、マクロfooは定義されません。
そのため、b.lispをコンパイルするときにfooは未束縛になってしまいます。
例えばAllegro CLであればコンパイル時に次のような警告が出ます。
Warning: While compiling these undefined functions were referenced:
FOO from character position 0 in b.lisp
Clozure CLであればこんな感じ。
;Compiler warnings for “b.lisp” :
; In BAR: Undefined function FOO
上記メッセージから分かるように、fooが関数扱いされるため、
この後、コンパイル済みのファイルをロードして、
(bar)
を評価するとエラーになります。
と こ ろ が、
SBCLやCLISPで同じ事をやると、問題なく動いてしまいます。
(compile-file "a.lisp") (compile-file "b.lisp") (load "b") (f) ; => (3 3)
コンパイル時に警告がでることもありません。
何が起こっているのか調べてみたところ、
compile-fileした時点で、マクロが定義されているみたいです。
(compile-file "a.lisp") (macro-function 'bar) ; => #<FUNCTION>
これは驚きです。
でも、ポータブルなコードでなくなるので、
こんなコードは書かないほうがいいでしょう。