Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 为什么dotrace在这里抛出堆栈溢出错误? 简言之:_Clojure - Fatal编程技术网

Clojure 为什么dotrace在这里抛出堆栈溢出错误? 简言之:

Clojure 为什么dotrace在这里抛出堆栈溢出错误? 简言之:,clojure,Clojure,这是因为trace fn call,这是dotrace用来包装要跟踪的函数的东西,它使用str生成nicetrace foo=>val输出 扩展解释: dotrace宏通过为每个Var安装一个线程绑定来实现它的魔力,该Var持有一个要跟踪的函数;在本例中,有一个这样的变量,clojure.core/str。替代方案大致如下: (use '[clojure.contrib.trace]) (dotrace [str] (reduce str [\a \b])) 用docstring的话来说,tr

这是因为
trace fn call
,这是
dotrace
用来包装要跟踪的函数的东西,它使用
str
生成nice
trace foo=>val
输出

扩展解释:
dotrace
宏通过为每个Var安装一个线程绑定来实现它的魔力,该Var持有一个要跟踪的函数;在本例中,有一个这样的变量,
clojure.core/str
。替代方案大致如下:

(use '[clojure.contrib.trace])
(dotrace [str] (reduce str [\a \b]))
用docstring的话来说,
trace fn调用“用args跟踪对函数f的单个调用”。在执行此操作时,它调用跟踪函数,记录返回值,打印一条格式为
TRACE foo=>val
的信息性消息,并返回从跟踪函数获得的值,以便可以继续正常执行

如上所述,此
TRACE foo=>val
消息是使用
str
生成的;然而,在本例中,这实际上是被跟踪的函数,因此对它的调用导致对
trace fn call
的另一个调用,该调用尝试使用
str
生成跟踪输出字符串,从而导致对
trace fn call
的另一个调用。。。最终导致烟囱爆炸

解决办法: 以下修改版本的
dotrace
trace fn call
即使在核心变量存在奇怪绑定的情况下也可以正常工作(请注意,未来可能无法及时安排;如果出现问题,请参阅下文):

(围绕常规的
dotrace
重新绑定
trace fn调用显然不起作用;我猜这是因为
clojure.
Var调用仍然是由编译器硬连接的,但这是另一回事。无论如何,上述操作都会起作用。)

另一种方法是将上述
my dotrace
宏与不使用期货的
my trace fn call
函数一起使用,但修改为使用以下函数代替
str
调用
clojure.contrib.trace
函数的自定义替换:

(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))

替换是简单而乏味的,我在答案中省略了它们。

这是否应该被视为一个bug,应该在哪里报告?或者我应该将str重新绑定到smth以实现这一点?这似乎至少是一个文档错误,尽管我有一些想法,可以对
c.c.trace
进行非颠覆性的修改,这将使它在面临核心变量反弹时更加健壮。。。我可能会考虑测试一些设计。目前,我已经在一个变通方案中进行了编辑,希望您能接受。我担心,直接重新绑定任何东西都是行不通的。
(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))
(defn my-str [& args] (apply (.getRoot #'clojure.core/str) args))