请在2024年Clojure状态调查中分享您的看法!

欢迎!请参阅关于页面以了解有关此功能的更多信息。

0
规范
考虑以下示例


$ clj
Clojure 1.9.0
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/def ::a int?)
:user/a
user=> (s/def ::b int?)
:user/b
user=> (s/def ::c int?)
:user/c
user=> (s/def ::d (s/and (s/keys :req [::a ::b ::c]) #(< (::a %) (::b %))))
:user/d
user=> (s/explain-data ::d {::a 1 ::b 0})
#:clojure.spec.alpha{:problems ({:path [], :pred (clojure.core/fn [%] (clojure.core/contains? % :user/c)), :val #:user{:a 1, :b 0}, :via [:user/d], :in []}), :spec :user/d, :value #:user{:a 1, :b 0}}
user=> (s/explain-data ::d {::a 1 ::b 0 ::c 2})
#:clojure.spec.alpha{:problems [{:path [], :pred (clojure.core/fn [%] (clojure.core/< (:user/a %) (:user/b %))), :val #:user{:a 1, :b 0, :c 2}, :via [:user/d], :in []}], :spec :user/d, :value #:user{:a 1, :b 0, :c 2}}


我想找到一种方法,以便第一次调用explain-data时包括缺失的::c和失败的<谓词。我明白spec/and被设计为短路,所以这可能可以通过一个新函数来解决,该函数独立地处理n个规范。

7 个回答

0
_由:alexmiller_发表的评论

在这种情况下,您可以使用s/merge,您将获得所有问题...


user=> (s/def ::e (s/merge (s/keys :req [::a ::b ::c]) #(< (::a %) (::b %))))
:user/e
user=> (s/explain ::e {::a 1 ::b 0})
val: #:user{:a 1, :b 0}失败规范::user/e谓词:(contains? % :user/c)
val: #:user{:a 1, :b 0}失败规范::user/e谓词:(< (:user/a %) (:user/b %))


s/merge具有“满足所有”的语义,但当然是针对映射的。
0

评论者:dchelimsky

明白了。我遇到的具体问题的另一个部分没有在这个示例中体现,那就是中间有一个constomer,它依赖于最后一个谓词。在那种情况下,s/merge不会起作用,因为constomer无法生成。您希望为这个单独的问题创建一张工单吗?

0

评论者:dchelimsky

我几乎用自定义生成器解决了这个问题。您希望留下这个工单吗?

0

评论者:alexmiller

关于constomer,答案是否定的,按照“满足所有条件而不流动”的设计,constomer值不会流入s/merge。至于是否留下,这取决于您。我们曾讨论过创建一个不流动和可变的东西,但我想没有为它创建工单。

0
评论者:dchelimsky

实际上,我只发现了一个与此相关的bug。继以上示例之后


user=> (s/explain ::e {::a 1 ::b 2})
val: #:user{:a 1, :b 2} 验证未通过 spec: :user/e 谓词: (contains? % :user/c)
val: #:user{:a 1, :b 2} 验证未通过 spec: :user/e 谓词: (< (:user/a %) (:user/b %))
nil


这应该会通过 {{(< (:user/a %) (:user/b %))}}
0

评论者:dchelimsky

我将为这个问题开一个单独的工单。

0
参考:[https://clojure.atlassian.net/browse/CLJ-2320](https://clojure.atlassian.net/browse/CLJ-2320)(由 dchelimsky 报告)
...