*描述*
如果您为一个函数添加了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的参数的spec)作为{{::s/spec}}
- 每一个问题在它们的{{:path}}中包含{{:args}}
这些事实可能会导致spec错误报告器的混淆,因为{{f}}({{(s/and integer? even?)}})的参数的spec没有与{{: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}}。