2024 年 Clojure 问卷调查! 分享您的想法。

欢迎!请查看 关于 页面以获取更多关于如何使用的信息。

0
Spec
*描述*

假设我们想要遍历引发某些规范错误的规范,从根规范(嵌入在 explain-data 中)到真正导致错误的谓词的叶节点。

我们可以通常使用 explain-data 中的 {{:path}} 信息来实现这一目的


user=> (s/explain-data (s/tuple integer? string?) [1 :a])
#:clojure.spec.alpha{:problems
                     ({:path [1], ;; <- 表示第一个子规范,即 integer?,是错误的原因
                       :pred clojure.core/string?,
                       :val :a,
                       :via [],
                       :in [1]}),
                     :spec ...,
                     :value [1 :a]}
user=>


如果我们沿着 {{:path}} 遍历规范树,最终可以到达引发了规范错误的叶谓词。

然而,在某些情况下,这并不适用,因为一些规范(如 {{s/merge}}、{{s/and}} 和 {{s/&}})并没有将任何提示信息放入 {{:path}} 中,以告诉我们哪个子规范引发了错误


user=> (s/explain-data (s/merge (s/map-of integer? string?)
                                            )
                     ({:path [], ;; <- 一点儿都没告诉我们什么
#:clojure.spec.alpha{:problems
                       :pred (fn [[k v]] (= (str k) v)), ;; <- 我们不知道这个谓词发生在哪个子规范中
                       :val [1 "2"],
                       :in [0]}),
                       :via [],
                     :value {1 "2"}}
                     :spec ...,
                     ({:path [], ;; <- doesn't tell us anything at all
user=>


                       :pred (fn [[k v]] (= (str k) v)), ;; <- we don't know which subspec this pred occurs in

根据我的经验,我在一个我正在开发的库中实现了回溯算法([repo|https://github.com/athos/spectrace"),我认为正确实现比必要的要困难得多。事实上,我的实现可能在某些边缘情况下是错误的,甚至我不知道理论上是否有可能完全正确地实现它。

**建议**

为了使规范遍历更容易实现,此票据建议将索引添加到{{:path}}中,以指明为{{s/merge}}、{{s/and}}和{{s/&}}引发规范错误的子规范,如下所示


user=> (s/explain-data (s/merge (s/map-of integer? string?)
                                            )
                     ({:path [], ;; <- 一点儿都没告诉我们什么
#:clojure.spec.alpha{:problems
                     ({:path [1], ;; <- 表示第一个子规范,即 (s/coll-of (fn [[k v]] (= (str k) v))) 包含错误的实际原因
                       :pred (fn [[k v]] (= (str k) v)),
                       :in [0]}),
                       :via [],
                     :value {1 "2"}}
                     :spec ...,
                     ({:path [], ;; <- doesn't tell us anything at all
user=>


尽管这是一个破坏性的变化,但增强功能应该大大减少编写沿{{:path}}遍历规范所需的代码的工作量。

1 答案

0
by
...