applyhook を使った profiler
を作ったんだけど*1、labels に対応できない。
applyhook に仕掛けた関数には、呼び出す関数とその呼び出しの引数が与えられるのだけど、呼び出す関数っつーか symbol が渡される。んで、その symbol が labels や flet で定義された lexical な関数だった場合にその関数を呼び出す方法が(パッと思いつく範囲では*2)無い。
コードで言うと、*applyhook* でやってることはたぶんこんな感じ。
;;; この関数 foo の呼び出しは (foo :bar "baz") ;;; こうフックされるのと同等 (funcall *applyhook* 'foo (list :bar "baz"))
なので、labels とかで foo を lexical な関数にしても
;;; この lexical な関数 foo の呼び出しは (labels ((foo (&rest args) ...)) (foo :bar "baz")) ;;; こうフックされるのと同等 (labels ((foo (list :bar "baz"))) (funcall *applyhook* 'foo (list :bar "baz")))
ちなみに global な関数と lexical な関数は別物で、symbol で指定できるのは global な関数のみ。lexical な関数は form の car に置くか #' でないと取り出せない。(前に書いたような気がしたけど書いてなかったっぽい。)
(defun foo () :global) => foo (labels ((foo () :lexical)) (values (foo) (funcall #'foo) (funcall 'foo) (funcall (symbol-function 'foo)))) => :lexical => :lexical => :global => :global
そんで *applyhook* の方は、それを呼び出すところとは完全に別の環境なので呼び出し側の lexical な関数にはアクセスできない。environment-object もらってもそっから lexical な関数を取り出す方法は無さそうなのに、そもそも environment-object が与えられない。
そうすると *applyhook* の中から applyhook とかでその関数を呼び出しても、本来の関数を呼び出すことができなくて、「関数が定義されていません」と怒られるか、こっそり global な関数を呼び出してくれやがるという困ったことに。
そんなわけで closette の profile を取れないとこがある。はぁーこまったこまった。
- closette から labels を取り除く
- labels に対応した profiler を作る
- profile をあきらめる
*1:ほとんど http://homepage3.nifty.com/~ko-ji/ のパクり
*2:*evalhook* では environment-object もらえるので、めんどいコトすればなんとかなるかもという気がしなくもない。