简而言之:
那是因为
trace-fn-call
,这是
dotrace
用于包装要跟踪的函数,使用
str
TRACE foo => val
输出。
扩展说明:
这个
点迹
宏通过为每个Var安装一个线程绑定来实现其魔力,该Var持有一个要跟踪的函数;在这种情况下,有一个这样的Var,
clojure.core/str
(let [f @
(fn [& args]
(trace-fn-call 'str f args)))
这个
跟踪fn呼叫
,引用其docstring,“用args跟踪对函数f的单个调用。”。在执行此操作时,它调用tracked函数,记录返回值,打印出表单的一条信息性消息
跟踪foo=>瓦尔
如上所述
跟踪foo=>瓦尔
; 然而,在本例中,这实际上是被跟踪的函数,因此对它的调用导致对它的另一个调用
跟踪fn呼叫
str公司
,这导致另一个呼叫
跟踪fn呼叫
... 最终导致烟囱爆炸。
点迹
和
跟踪fn呼叫
即使核心变量存在奇怪的绑定,也应该可以正常工作(注意未来可能不会及时安排;如果有问题,请参见下文):
(defn my-trace-fn-call
"Traces a single call to a function f with args. 'name' is the
symbol name of the function."
[name f args]
(let [id (gensym "t")]
@(future (tracer id (str (trace-indent) (pr-str (cons name args)))))
(let [value (binding [*trace-depth* (inc *trace-depth*)]
(apply f args))]
@(future (tracer id (str (trace-indent) "=> " (pr-str value))))
value)))
(defmacro my-dotrace
"Given a sequence of function identifiers, evaluate the body
expressions in an environment in which the identifiers are bound to
the traced functions. Does not work on inlined functions,
such as clojure.core/+"
[fnames & exprs]
`(binding [~@(interleave fnames
(for [fname fnames]
`(let [f# @(var ~fname)]
(fn [& args#]
(my-trace-fn-call '~fname f# args#)))))]
~@exprs))
跟踪fn呼叫
有规律的
clojure.*
Var调用仍由编译器硬连接,但这是另一回事。不管怎样,上面的方法还是可以的。)
my-dotrace
宏与
my-trace-fn-call
函数不使用futures,但已修改为调用
clojure.contrib.trace
使用以下函数代替
(defn my-str [& args] (apply (.getRoot
替换是直接和乏味的,我省略了他们的答案。