谓词函数的 Clojure 规范

A Clojure Spec for a predicate function

我想为函数作为谓词的含义编写规范。在 Clojure 世界中似乎有三种方法可以解释谓词是什么,尽管大多数人似乎都同意它们应该以问号结尾。

  1. 一个接受一个参数和 returns true 或 false 的函数。
  2. 一个接受一个参数和 returns true、false 或 nil 的函数。
  3. 一个接受一个参数和 returns 真值或假值的函数。

Jira Ticket on what Predicate is.

编辑:谓词也可以采用多个参数,例如 contains?

如果我理解 clojure.spec/fdef 更正它允许我们制定问题中描述的规范。

(spec/fdef ::predicate-1
           :args (spec/cat :arg any?)
           :ret  boolean?)

我们可以通过传递一些我们知道应该通过或未通过测试的示例来测试它:

(spec/valid? ::predicate-1 boolean?)       => true
(spec/valid? ::predicate-1 (fn [a] 5))     => false
(spec/valid? ::predicate-1 (fn [a] true))  => true
(spec/valid? ::predicate-1 (fn [a b] true))=> false
(spec/valid? ::predicate-1 #(= 10 %))      => true
(spec/valid? ::predicate-1 (fn [a] nil))   => false

对于防御编号。 2:

(spec/fdef ::predicate-2
           :args (spec/cat :arg any?)
           :ret  (spec/nilable boolean?))

(spec/valid? ::predicate-2 (fn [a] nil))   => true

对于 nr。 3 任何接受一个参数的函数都是有效的,因为 clojure 中的所有内容要么为真,要么为假。

(spec/fdef ::predicate-3
           :args (spec/cat :arg any?)
           :ret  any?)

(spec/valid? ::predicate-3 identity)       => true
(spec/valid? ::predicate-3 str)            => true

然后我们似乎能够做的一件有趣的事情是让规范为我们生成这样的函数:

(let [p (gen/generate (spec/gen ::pedicate-1))]
  (clojure.string/join
   " " [(p 0) (p 1) (p -1) (p nil) (p 'a) (p :a) (p (fn [a] a))]))
=> "false true true false true false false"

由此我们或许可以尝试猜测生成的函数的作用。但是如果看不到来源,我们将很难检查我们的猜测是否正确。

我认为谓词最准确的规范是:

(s/fspec :args (s/cat :v any?) :ret any?)

虽然谓词通常 return true/false,但并不要求它们这样做 - 唯一需要的约定是它采用一个值,并且 returns 是一个值被视为逻辑真值。