分享您的想法,请参加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个规格的新的函数来解决。

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})
值:#:user{:a 1, :b 0} 无法满足规格::user/e 谓词:(contains? % :user/c)
值:#:user{:a 1, :b 0} 无法满足规格::user/e 谓词:(< (:user/a %) (:user/b %))


s/merge具有“满足所有”的含义,但当然特定于地图。
0

评论由:dchelimsky 发布

明白了。我具体问题的另一部分没有体现在这个示例中,那就是我在中间有一个符合者,是最后一个谓词所依赖的。在那种情况下,s/merge 不会工作,因为符合者无法生成。你希望为这一点单独创建一个问题吗?

0

评论由:dchelimsky 发布

因此,我用自定义生成器来工作,接近成功了。你想要保持这个问题开放吗?

0

评论由:alexmiller 发布

关于符合者 - 不,符合值不流动到 s/merge 是出于设计考虑(且与“满足所有”相伴的理念相一致)。关于留下开放,那取决于你了。我们曾讨论过创建一个不流动且可变的(non-flowing and variant),但没有关于它的票据。

0
_评论由: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

评论由:dchelimsky 发布

我将为该问题单独创建一个问题。

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