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 もらえるので、めんどいコトすればなんとかなるかもという気がしなくもない。