2024年Clojure状态调查!中分享您的想法。

欢迎!有关此操作信息的更多信息,请参见关于页面。

0
特制
当一个函数的宏编程失败时,explain-data 包含 "调用者" 信息。但是,如果宏编程失败是对宏而言,该信息将不存在。

这条评论使我相信,预期行为是 explain-data 应包含此信息,以便第三方错误打印机可以显示它。

在下面的重复中,我设置了一个自定义打印机来仅捕获原始 explain-data(它不是一个有用的打印机,只是一个显示发生什么的手段)

重复


  (require '[clojure.spec.alpha :as s])
  (require '[clojure.spec.test.alpha :as st])
  (require '[clojure.specs.alpha :as s])


  (s/fdef my-fn
          :args (s/cat :x int?))
  (defn my-fn [x]
    x)

  (s/fdef my-macro
          :args (s/cat :x int?))
          (defmacro my-macro [x]
    x)

  (st/instrument)
  (def !ed (atom nil))
  (set! s/*explain-out* (fn [ed]
                                      (reset! !ed ed)))
  (my-fn "")
  @!ed
  ;; {:clojure.spec.alpha/problems [{:path [:args :x], :pred clojure.core/int?, :val "", :via [], :in [0]}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x72029b0e "clojure.spec.alpha$regex_spec_impl$reify__2436@72029b0e"], :clojure.spec.alpha/value (""), :clojure.spec.alpha/args (""), :clojure.spec.alpha/failure :instrument, :clojure.spec.test.alpha/caller {:file "form-init8333540581183382896.clj", :line 548, :var-scope expound.alpha/eval27394}}

  ;; ^--- 注意存在 :clojure.spec.test.alpha/caller 的条目

  (my-macro "")
  @!ed

  ;; #:clojure.spec.alpha{:problems [{:path [:args :x], :pred clojure.core/int?, :val "", :via [], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x479a6a73 "clojure.spec.alpha$regex_spec_impl$reify__2436@479a6a73"], :value (""), :args ("")}

  ;; ^--- 没有调用者信息

10 答案

0

评论者:alexmiller

您不能对宏进行宏编程,因此,所写票务的部分是没有意义的。但我预计你的意思是在宏展开期间的规格检查。

在宏检查案例中,调用者信息由编译器知道,并包含在包装器编译器异常中。我猜这些信息可以被传递给s/macroexpand-check,可能产生与instrumented函数调用相似的结果。

0

评论者:bbrinck

啊,你说对了,谢谢你的澄清。

如果添加了调用者信息,对于在宏展开期间失败的规范,添加特定的:clojure.spec.alpha/failure值也将非常有用。这将允许第三方工具在宏展开失败时显示特定的错误消息类型。

0

评论者:bbrinck

此外,访问宏名称的符号将有助于错误报告。

0

评论者:sohta

在我看来,对于instrumentation失败和宏规范错误,{{explain-data}}应该包含函数(或宏)的fspec,就像我在CLJ-2218中之前建议的那样。

{{fspec}}有一些有用的信息(例如,规范函数的ns-qualified名称符号和行号等),在它的元数据中,所以规范错误报告器可以用它们以统一的方式为instrumentation失败和宏规范错误提供更丰富、更精确的错误消息。

0

评论者:alexmiller

在CLJ-2373之后,对于规范宏失败的调用者信息将通过包装器CompilerException传递(与其他编译器和宏展开错误一样)。应考虑这个问题是否因此得以有效解决。

0

评论者:bbrinck

我很高兴听到这将被包含在CompilerException中,但我认为将其包含在spec explain-data中仍然是有用的。

在打印规范错误时,如果能够以类似格式打印宏扩展规范错误和仪表错误(如果用户选择自定义规范打印机),将会更加清晰。在一个地方查找宏扩展错误的信息,在另一个地方查找仪表错误的信息可能会造成中断。

此外,规范打印机可以选择用新颖的方式处理调用者信息,例如为输出添加颜色或打印实际代码而不是行号。如果提供给规范打印机这些信息由其自定义,那将会非常好。

0

评论者:alexmiller

问题是,当宏规范错误创建时,我们没有任何方法知道正确的调用者信息。在那个点,堆栈是编译器宏扩展,不是调用代码。宏扩展知道这个上下文,并且在包装着 CompilerException 时会添加这个上下文(这就是 CompilerException 的主要用途)。

我认为为了改变这一点,我们需要将信息通过带外传递到规范检查中。好吧,也许这是可能的。我会再看看。

0

评论者:bbrinck

通过最近错误消息的工作(优异的工作!),符号似乎可用,但目前并没有将其传递给 "explain-out" 函数:[链接](https://github.com/clojure/clojure/blob/b182982007df934394f0bc68b3a238ca9f200dd1/src/clj/clojure/main.clj#L268-L279)

是否有可能将这个“assoc”到传递给 "spec/explain-out" 的 "spec" 中?这将允许自定义打印机引用规范名称,这将非常有用。

另一种方法是让用户在 REPL 中设置自定义错误处理程序,但这比设置 "explain-out" 的第三方实现要复杂得多。

0
_由 alexmiller发表的评论_

我都不希望这只能由 clojure main repl 使用——如果是其他 repl 也会更好,最好在构造时这样做。我现在对这个有了更好的理解,但不知道是否太晚了,不能用于 1.10。
0
参考:[链接](https://clojure.atlassian.net/browse/CLJ-2271)(由 bbrinck 报告)
...