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

欢迎!请参阅关于页面了解更多关于这个网站的详细信息。

0
Spec
考虑以下示例


$ 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个spec来解决这个问题。

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} 未能通过spec: :user/e 谓词: (contains? % :user/c)
val: #:user{:a 1, :b 0} 未能通过spec: :user/e 谓词: (< (:user/a %) (:user/b %))


s/merge具有"满足所有"的语义,但当然特定于映射。
0
by

评论由:dchelimsky 发表

明白了。我具体问题的另一部分没有在这例子中反映,我在中间有一个构体依赖于最后的谓词。在那种情况下,s/merge 不会工作,因为构体无法生成。您想要为这个问题创建单独的问题吗?

0
by

评论由:dchelimsky 发表

因此,我使用自定义生成器接近实现。您想要保留这个问题吗?

0
by

评论由:alexmiller 发表

关于构体:不对,为了满足所有,有意让构体值不流向 s/merge(并与“不流向”概念一致)。至于是否保留,那取决于你。我们讨论过创建一个不流向的变体,但我不认为有一个对应的工单。

0
by
_评论由:dchelimsky_ 发表

实际上,我刚刚发现了一个与此相关的错误。在上述例子之后


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
by

评论由:dchelimsky 发表

我将为这个问题创建单独的问题。

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