Clojure 堆栈跟踪和动态内部变量

Clojure stacktraces and dynamically interned vars

我有 Clojure 代码并对它求值,然后将它存入一个 var:

(let [x (binding [*ns* my-ns] (eval m-code))]
  (intern my-ns my-sym x)) ; my-sym was declared beforehand. 

但是当 x 内发生错误时,trace 没有引用 x:

my-ns/eval27298/fn--27299
...

我复制了一个更“标准”的变量的元数据,但这并没有改变堆栈跟踪:

(alter-meta! my-var #(assoc % :line 1 :column 1 :file "my_ns.clj" :name my-sym :ns my-ns))

如果不是元数据,用什么来确定堆栈跟踪?

除非我记错了,否则它是这样工作的:

  1. reader 读取您的代码并将所有位置元数据分配给 vars
  2. 然后对代码进行评估,元数据不仅用于报告代码加载期间的错误,还用于报告在评估本身之后使用评估的功能时发生的任何错误

鉴于此,alter-meta! 无法工作,因为所有位置都已被处理并记住。可以工作的是在上面的步骤 1 和 2 之间分配元数据:

user=> (def code "#(throw (ex-info \"\" {}))")
#'user/code
user=> (def f (eval (-> (read-string code) (with-meta {:line 42, :clojure.core/eval-file "hello.clj"}))))
#'user/f
user=> (f)
Execution error (ExceptionInfo) at user/eval175$fn (hello.clj:42).

请注意,我使用 :clojure.core/eval-file 来指定文件,而不仅仅是 :file