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

欢迎!请参阅 关于 页面以了解更多有关此如何工作的情况。

0
规范
此问题在该讨论的上下文中被发现 https://groups.google.com/d/msg/clojure/mIlKaOiujlo/tF71zZ2BCwAJ

关于 specs 错误报告失败的示例,看起来是这样的

他使用了无效的 ns 形式

(ns foo (require [clojure.spec :as s])) ; 应该是 :require
 

spec 报告的错误

在:[1] val: ((require [clojure.spec :as s])) 在:[:args] 断言:(:docstring (? string?) :attr-map (? map?) :clauses :clojure.core.specs/ns-clauses),  额外输入
:clojure.spec/args  (foo (require [clojure.spec :as s]))
  clojure.core/ex-info (core.clj:4725)


尽管错误在技术上是真实的,但它并没有显示用户报告的每个 s/cat 的替代选项是如何失败的。

为了更好地了解用户数据为什么会错误,他应该确切知道 spec 所尝试的以及如何失败。

一个如何工作的良好例子是 s/alt,其中所有失败的替代选项都会始终报告给用户。

首先通过实验,然后在 specs 代码中进行调查,这个问题已经被研究。  最后,一个上传的补丁实现了类似于 s/alts 的错误报告。

对于具有可选分支的 cat 的 specs 错误报告行为的观察如下

1. 如果 cat 在一个或多个可选分支之后失败,整个 cat 被报告为失败
2. 如果 cat 在一个或多个可选分支之后/并/后续有必填分支失败,只有后续的必填分支被报告,对替代的可选分支没有说明。

规则 1 解释了 ns 的例子。
规则 2 的失败可能会导致用户的直觉有更坏的情况


(s/explain (s/cat :maybe-num (s/? number?'
                   :keyword keyword?)
            ["3"])


给出


在:[0] val: "3" 在:[:keyword] 断言:keyword?


报告清楚地没有提及用户想要输入数字。  相反,他会被误导,认为他应该输入关键字。

解决方案

已经编写了一个简单的补丁,它将 op-explain 修改为以下行为

- 均报告 s/cat 中已尝试的所有替代选项。

这显著改进了报告的错误,因为它清晰地显示了用户数据如何未通过验证。


(ns foo (require [clojure.spec :as s])) ; 应该是 :require
 

现在给出


ExceptionInfo 对 clojure.core/ns 的调用不符合规范
在:[1] val: (require [clojure.spec :as s]) 在:[:args :docstring] 断言:string?
在:[1] val: (require [clojure.spec :as s]) 在:[:args :attr-map] 断言:map?
在:[1 0] val: require 不符合规范::clojure.core.specs/ns-refer-clojure 在:[:args :clauses :refer-clojure :clause] 断言:#{:refer-clojure}
输入:[1 0] 值:require 失败,规范::clojure.core.specs/ns-require 在位置:[:args :clauses :require :clause],谓词:#{:require}
输入:[1 0] 值:require 失败,规范::clojure.core.specs/ns-import 在位置:[:args :clauses :import :clause],谓词:#{:import}
输入:[1 0] 值:require 失败,规范::clojure.core.specs/ns-use 在位置:[:args :clauses :use :clause],谓词:#{:use}
输入:[1 0] 值:require 失败,规范::clojure.core.specs/ns-refer 在位置:[:args :clauses :refer :clause],谓词:#{:refer}
输入:[1 0] 值:require 失败,规范::clojure.core.specs/ns-load 在位置:[:args :clauses :load :clause],谓词:#{:load}
输入:[1 0] 值:require 失败,规范::clojure.core.specs/ns-gen-class 在位置:[:args :clauses :gen-class :clause],谓词:#{:gen-class}
:clojure.spec/args  (foo (require [clojure.spec :as s]))
  clojure.core/ex-info (core.clj:4725)


如果 explain-data 能够根据 ::s/problems 的 :path 长度进行排序,这将把前两个非预期选项移至末尾,会更好。


(s/explain (s/cat :maybe-num (s/? number?'
                   :keyword keyword?)
            ["3"])


现在给出


输入:[0] 值:"3" 失败,在位置:[:maybe-num],谓词:number?
在:[0] val: "3" 在:[:keyword] 断言:keyword?


虽然可以构建一些示例,其中这种报告会产生更多的噪音(如 defn),但我相信由于上述原因,这是正确的权衡。

- 当出现问题时,我们程序员总是要求用户提供最具体的信息 - 将其应用到规范错误报告中是正确的
- 自定义错误报告器(s/*explain-out*)可以获得更多信息,从而更好地生成符合用户意图的所需报告

7 个答案

0
_由 visibletrap 添加的评论_

我将在此处提出一个略有不同的问题,因为它具有相同的原因。

应明确指出 fspec 的 :ret 缺失,但它说在 :args 处失败。


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

(defn x [f] (f 1))

(s/fdef x
  :args (s/cat :f (s/fspec :args (s/cat :i int?))))

(st/instrument `x)

(x (fn [a] a))



主线程异常:clojure.lang.ExceptionInfo:#'user/x 的调用不符合规范
输入:[0] val: (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]) 在位置:[:args],谓词::(cat :f (fspec :args (cat :i int?))), 多余输入
:clojure.spec/args (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"])
:clojure.spec/failure (:instrument)
:clojure.spec.test/caller {:file "debug.clj", :line 16, :var-scope user/eval20}
{:clojure.spec/problems [{:path [:args], :reason "Extra input", :pred (cat :f (fspec :args (cat :i int?))), :val (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]), :via [], :in [0]}], :clojure.spec/args (#object[user$eval20$fn__21 0x3e521715 "user$eval20$fn__21@3e521715"]), :clojure.spec/failure (:instrument,),}
...
0

_由 lgs32a 添加的评论_

对于alexmiller:在发布1.9版本之前决定这个怎么样?因为这将在很大程度上改善错误信息。自从在小组中进行了原始讨论之后,我们收到了更多关于不直观的错误信息的报告,这将会解决这个问题。与此相关的是按路径长度排序说明,如图所示(这方面还没有票据)。
请征求Rich的看法。

0

评论人士:gshayban

目前正在规范和独立git repo中进行工作,该repo不受Clojure 1.9发布的影响。我们将能够独立于Clojure更新spec依赖项,并最终收到修复。

0

_由 lgs32a 添加的评论_

这会影响Clojure的编译时错误信息,而不仅是spec的opt-in部分。这部分编译器错误报告是损坏的,不应与主要版本一起发布。在这方面,spec是单独的依赖项还是不是并不重要。

此外,等待spec稳定版本的用户新实不一定会更新他们的spec依赖项。

0

_由 lgs32a 添加的评论_

据我所知,更好的错误报告是Spec成为1.9依赖项的唯一理由。请重新考虑。

0

评论人士:alexmiller

我不知道这是否会在1.9之前或之后被考虑。根据我所读的内容,这似乎是合理的。

已应用于CLJ-2063的按路径长度排序说明,该说明于5月份发布并在spec.alpha 0.1.109中发布。

0
参考:https://clojure.atlassian.net/browse/CLJ-2013(由lgs32a报告)
...