Clojure 1.2.0 で再帰的呼び出しを dotrace で補足できない件

dotrace マクロを使うと、指定した関数の呼び出しの引数、返り値をトレースできる。

user> (use 'clojure.contrib.trace)
nil
user> (defn f [n] (* n n))
#'user/f
user> (dotrace [f] (doseq [i [1 2 3]] (f i)))
TRACE t7412: (f 1)
TRACE t7412: => 1
TRACE t7413: (f 2)
TRACE t7413: => 4
TRACE t7414: (f 3)
TRACE t7414: => 9
nil

のだが、 Clojure 1.2.0 では、再帰的呼び出しに対して dotrace がうまく動かなくなってしまった。

user> (defn fact [n] (if (< n 2) n (* n (fact (dec n)))))
#'user/fact
user> (dotrace [fact] (fact 5))
TRACE t7499: (fact 5)
TRACE t7499: => 120
120

Clojure 1.1.0 だと、以下のようにきれいに表示される。

user> (use 'clojure.contrib.trace)
nil
user> (defn fact [n] (if (< n 2) n (* n (fact (dec n)))))
#'user/fact
user> (dotrace [fact] (fact 5))
TRACE t14: (fact 5)
TRACE t15: |    (fact 4)
TRACE t16: |    |    (fact 3)
TRACE t17: |    |    |    (fact 2)
TRACE t18: |    |    |    |    (fact 1)
TRACE t18: |    |    |    |    => 1
TRACE t17: |    |    |    => 2
TRACE t16: |    |    => 6
TRACE t15: |    => 24
TRACE t14: => 120
120

で、何故なんだろうと調べてみると、 Can clojure be made fully dynamic? - Stack Overflow に突き当たった。

どうやら、関数内では、その関数自身の名前を Var として名前解決するのではなく、lexical binding として持つようになったらしい。従って、 dotrace が動的に Var を既存の関数をラップした新しい関数で再束縛しても、再帰的呼び出し部分は、常に名前解決の優先順位の高い lexical binding ( lexical binding は再束縛できない ) を見ていて、変更された Var のほうを見ることができない、ということらしい。
そのため、 dotrace で再帰的な呼び出しを補足したい場合は、定義内の再帰的呼び出しを Var で名前解決するように #'var と指定してやる必要がある。

user> (defn fact2 [n] (if (< n 2) n (* n (#'fact2 (dec n)))))
#'user/fact2
user> (dotrace [fact2] (fact2 5))
TRACE t14091: (fact2 5)
TRACE t14092: |    (fact2 4)
TRACE t14093: |    |    (fact2 3)
TRACE t14094: |    |    |    (fact2 2)
TRACE t14095: |    |    |    |    (fact2 1)
TRACE t14095: |    |    |    |    => 1
TRACE t14094: |    |    |    => 2
TRACE t14093: |    |    => 6
TRACE t14092: |    => 24
TRACE t14091: => 120
120