在你认为的地方分享你的想法!请填写2024 Clojure状态调查问卷

欢迎!有关如何操作的更多信息,请参阅关于页面。

+1
Spec
编辑

我在使用Clojure 1.11.1中的spec.alpha

(require '[clojure.spec.alpha :as s])

添加spec ::foo,其中包含三个表示"别名"另一个spec的方式的spec(直接、s/spec、s/and)。

(s/def ::foo int?)

(s/def ::bar      ::foo)
(s/def ::bar-spec (s/spec ::foo))
(s/def ::bar-and  (s/and ::foo))
  • 与文档相关的問題

只有::bar-and spec保留关于别名的信息。

(s/form ::bar)      ;=> clojure.core/int?
(s/form ::bar-spec) ;=> clojure.core/int?
(s/form ::bar-and)  ;=> (clojure.spec.alpha/and :user/foo)

我发现这很有用,例如,"查找::foo spec的使用情况"很简单。

  • 与生成器覆盖相关的问题

添加spec ::m,它聚合来自上方的spec。

(s/def ::m (s/keys :req [::foo ::bar ::bar-spec ::bar-and]))

覆盖底层::foo spec的数据生成器对::bar-spec别名不起作用。

(gen/generate (s/gen ::bar      {::foo (fn [] (gen/return 0))})) ;=> 0
(gen/generate (s/gen ::bar-spec {::foo (fn [] (gen/return 0))})) ;=> -2
(gen/generate (s/gen ::bar-and  {::foo (fn [] (gen/return 0))})) ;=> 0

(gen/generate (s/gen ::m {::foo (fn [] (gen/return 0))}))
;=> #:user{:foo 0, :bar 0, :bar-spec 31, :bar-and 0}

在直接别名::bar的情况下,覆盖别名spec的生成器不起作用。

(gen/generate (s/gen ::bar      {::bar      (fn [] (gen/return 0))})) ;=> -492158
(gen/generate (s/gen ::bar-spec {::bar-spec (fn [] (gen/return 0))})) ;=> 0
(gen/generate (s/gen ::bar-and  {::bar-and  (fn [] (gen/return 0))})) ;=> 0

(gen/generate (s/gen ::m
                     {::bar      (fn [] (gen/return 0))
                      ::bar-spec (fn [] (gen/return 0))
                      ::bar-and  (fn [] (gen/return 0))}))
;=> #:user{:foo 183249700, :bar -1, :bar-spec 0, :bar-and 0}

覆盖::bar生成器的唯一方法是覆盖::foo的生成器。但是,这也会影响所有::foo的别名,这并不总是人们所希望的。


我最喜欢s/and的行为,但它的定义可能是最令人困惑的,因为听起来像s/and应该有多个参数。

这两类方法行为背后的原理是什么?
这是预期的吗?
有没有其他定义别名的方法?
这是否会在将来的spec中得到修改?

1 个回答

0

其定义可能是用户最困惑的部分,因为它听起来像是s/and应该有多个参数。

这正是情况。 s/andand 类似 - 最常见的用法是与多个参数一起使用,尽管您可以只传递一个,甚至一个也不传。

...