数字?不能在规范中使用

number? can't be used in spec

在 Clojure 1.9.0-alpha13 中,我可以使用 spec/andinteger? 而不是 andnumber? 来定义规范谓词,它出现了。这令人费解。同样令人费解的是,当我定义谓词时没有错误,但只有当我尝试使用它来定义规范时才会出现错误。

user=> (use '[clojure.spec :as s])
...
nil
user=> (s/def pos-int? (s/and integer? pos?))
user/pos-int?
user=> (s/def ::foo pos-int?)
:user/foo
user=> (s/def pos-num? (s/and number? pos?))
user/pos-num?
user=> (s/def ::bar pos-num?)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: pos-num? ...

为什么我在第二种情况下会出错,而在第一种情况下却不会?这是一项涉及我不知道的区别的功能,还是一个错误?

注意我直接定义::bar不会报错:

user=> (s/def ::bar (s/and number? pos?))
:user/bar

我相信您已经发现了与来自 clojure.core 的预定义 pos-int? 的交互。源代码中:

src/clj/clojure/core.clj 第 1400 行

(defn pos-int?
  "Return true if x is a positive fixed precision integer"
  {:added "1.9"}
  [x] (and (int? x)
           (pos? x)))

没有pos-num?存在。

您的代码不正确。 s/def 应使用限定关键字调用以注册规范,而不是符号。

所以这个:

user=> (s/def pos-int? (s/and integer? pos?))
user/pos-int?

并没有按照您的想法行事。它实际上是在符号 user/pos-int?.

下注册一个函数定义(您通常通过 s/fdef 进行)
user=> (s/def ::foo pos-int?)
:user/foo

这是可行的,因为 pos-int? 是 clojure.core 中的一个现有函数(也就是说,它根本没有使用您之前的定义)。

这似乎也有效,但同样不正确:

user=> (s/def pos-num? (s/and number? pos?))
user/pos-num?

这失败了:

user=> (s/def ::bar pos-num?)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: pos-num? ...

因为 pos-num 不是 现有谓词。

假设您想注册两个正整数和数字规范,您可以这样做:

(s/def ::pos-int (s/and integer? pos?))
(s/def ::pos-num (s/and number? pos?))