2024 年 Clojure 现状调查! 中分享您的想法。

欢迎!有关本平台的更多信息,请查看关于页面。

+1
Spec
编辑于

我正在使用 Clojure 1.11.1 版本的 spec.alpha

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

添加代表“别名”另一个规范的方式(直接、s/spec、s/and)的三个规范 ::foo

(s/def ::foo int?)

(s/def ::bar      ::foo)
(s/def ::bar-spec (s/spec ::foo))
(s/def ::bar-and  (s/and ::foo))
  • 文档问题

只有 ::bar-and 规范保留了别名信息。

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

我发现这很有用,例如,“查找” ::foo 规范的用法非常简单。

  • 生成器覆盖问题

添加将上述规范汇总的规范 ::m

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

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

(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 的情况下,覆盖别名规范的生成器不起作用。

(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 的行为,但它对于其他用户来说可能是最令人困惑的,因为它的定义听起来应该有多个参数。

其他两种方法行为的理由是什么?
这是预期的吗?
还有其他定义别名的方法吗?
在未来的规范中会进行更改吗?

1 答案

0

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

这正是这种情况。 s/andand 类似 - 最常见的用法是带有多个参数,虽然你也可以传入一个,甚至 none。

...