代码之家  ›  专栏  ›  技术社区  ›  Michiel Borkent

为什么dotrace在这里抛出堆栈溢出错误?

  •  7
  • Michiel Borkent  · 技术社区  · 15 年前
    (use '[clojure.contrib.trace])
    (dotrace [str] (reduce str [\a \b]))
    
    1 回复  |  直到 15 年前
        1
  •  9
  •   Michał Marczyk    15 年前

    简而言之:

    那是因为 trace-fn-call ,这是 dotrace 用于包装要跟踪的函数,使用 str TRACE foo => val 输出。

    扩展说明:

    这个 点迹 宏通过为每个Var安装一个线程绑定来实现其魔力,该Var持有一个要跟踪的函数;在这种情况下,有一个这样的Var, clojure.core/str

    (let [f @#'str]
      (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 #'clojure.core/str) args))
    

    替换是直接和乏味的,我省略了他们的答案。