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

欢迎!有关如何使用本网站的更多信息,请参阅关于页面。

0
Spec
*描述*

如果你针对一个函数进行了instrument操作,你可能会遇到以下这样的spec错误:


(defn f [x] (inc x))
(s/fdef f
  :args (s/cat :x (s/and integer? even?))
  :ret (s/and integer? odd?))

({:t/instrument})

(f 3)
;; ExceptionInfo 调用#'#user/f不符合spec
;; In: [0] val: 3 在[:args :x]处违反:even?
;; :clojure.spec.alpha/spec  #object[clojure.spec.alpha$regex_spec_impl$reify__1200
 0x19b3f9a "clojure.spec.alpha$regex_spec_impl$reify__1200@19b3f9a"]
;; :clojure.spec.alpha/value  (3)
;; :clojure.spec.alpha/args  (3)
;; :clojure.spec.alpha/failure  :instrument
;; :clojure.spec.test.alpha/caller  {:file "form-init3240393046310519022.clj", :lin
e 1, :var-scope user/eval1413}
;; clojure.core/ex-info (core.clj:4725)

(ex-data *e)
;; {:clojure.spec.alpha/problems
;;   [{:path [:args :x],
;;     :pred clojure.core/even?,
;;     :val 3,
;;     :via [],
;;     :in [0]}],
;;  :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__1200 0x19b3f9a "clojure.spec.alpha$regex_spec_impl$reify__1200@19b3f9a"],
;;  :clojure.spec.alpha/value (3),
;;  :clojure.spec.alpha/args (3),
;;  :clojure.spec.alpha/failure :instrument,
;;  :clojure.spec.test.alpha/caller {:file "form-init3240393046310519022.clj", :line 1, :var-scope user/eval1413}}


正如你所看到的,

- explain-data 包含一个正则表达式(即 f 的args的spec),它是{::s/spec}
- 每个问题中 {{:args}} 在它们的 {{:path}} 中

这些事实可能会导致spec错误报告器混淆,因为 f 的args的spec ({{(s/and integer? even?)}})没有与 {{:args}} 对应的子spec(我认为 {{:path}} 应该只包含能够指示从spec中选择哪个子spec的键)。

*可能的解决方案*

要解决这个问题并提高instrument检查的explain-data一致性,我认为有两个选项如下

- *解决方案 1.* 从 {{:path}} 中移除 {{:args}}
- *解决方案 2.* 修改instrument检查的explain-data,使其具有fspec(而不是它的 {{:args}})作为 {{::s/spec}}

我个人更喜欢 *解决方案 2.* 因为在explain-data中添加fspec可以使得提供给 {{\*explain-out\*}} 实现者更丰富的错误信息成为可能。

同样适用于 {{macroexpand-check}}。

6 答案

0

评论由:alexmiller

这里的fspec是我们所提到的问题规范,并且它确实有一个组件:args(fspec实例支持通过ILookup对:args进行键查找)。因此,尽管我想改进错误信息和数据,但我并不赞同从路径中删除:args。我认为有一件很有用的事情是在仪表(instrumentation)失败时能更好地表达调用(将函数和参数组合进入原始调用)。目前它们是分开的,需要一些思维工作才能将参数列表重新组合在一起。

0

评论由:sohta

{quote}
尽管我想改进这里的错误信息和数据,但我并不赞同从路径中删除:args。
{quote}

是的,一旦我们决定采用方案2,我认为就没有必要从:path中删除{{:args}}。

{quote}
我认为有一件很有用的事情是在仪表(instrumentation)失败时能更好地表达调用(将函数和参数组合进入原始调用)。
{quote}

我完全同意这很有用,尽管听起来这似乎在一定程度上超出了这个票证(ticket)的范畴,因为要提高一致性。

0

评论由:sohta

我已编写了一个补丁来表述我的意思。任何反馈都将受到欢迎。

0

评论由:bbrinck

{quote}
我认为有一件很有用的事情是在仪表(instrumentation)失败时能更好地表达调用(将函数和参数组合进入原始调用)。目前它们是分开的,需要一些思维工作才能将参数列表重新组合在一起。
{quote}

如果漏掉了什么,请见谅,但我看解释数据(explain-data)中是否可以得到函数?我看不出解释数据中有这个,但也许可以以某种方式恢复。无论如何,如果这种类型的信息可用,这将使得打印更清晰的错误信息成为可能。

0
by

评论由:sohta

嘿,这已经由 CLJ-2392 做过了吗? :)

0
by
参考: https://clojure.atlassian.net/browse/CLJ-2218(由 sohta 报告)
...