Clojure:检查函数是否具有某些post(或pre)条件

时间:2018-02-11 21:49:58

标签: validation clojure

问题

在Clojure中,可以使用ifn?检查变量是否代表一个函数。

我问自己,如果有办法检查var是否是具有某些后置(或预置)条件的函数。

奖励:是否可以构建要参数化检查的后置条件?

示例

假设foo代表一个函数(即(ifn? foo)返回true)。 如何检查foo是否有某个帖子条件,例如它返回010之间的数字。换句话说,我如何检查foo是否具有以下后置条件?

{:post (and (number? %) (<= 0 %) (<= % 10))

加分:是否可以检查N而不是10,其中N是我可以选择的参数?

{:post (and (number? %) (<= 0 %) (<= % 10))

背景

我是implementing Bloom-filter data structure,如果我可以验证哈希函数,那将是非常好的。 (即,它们是函数,仅返回Bloom过滤器中0bits之间的数字。)

说明

我已经知道一些解决方法,例如比如将哈希函数包装在包含后置条件的其他函数中,或者取其位数的模数。虽然我感谢上述用例的任何进一步的解决方法,但请包括对主要问题的明确答案(即“是否可以检查函数是否具有某种后置条件?”)。 “不,这是不可能的”也是我当然可以接受的答案。

1 个答案:

答案 0 :(得分:2)

  

[有]一种方法来检查var是否是具有某些post(或pre)条件的函数

是的,在this Q&A的基础上,我们可以这样做:

(defn fn->pre-post [fvar]
  (-> fvar meta :arglists first meta (select-keys [:pre :post])))

编写一个函数,将函数var和列表形式与其:post条件进行比较:

(defn some-post? [fvar post]
  {:pre [(var? fvar)]}
  (some #(= post %) (-> fvar fn->pre-post :post)))

然后我们可以测试函数是否具有我们期望的:post条件:

(defn foo [n]
  {:post [(and (number? %) (<= 0 %) (<= % 10))]}
  (* n n))

(some-post?
  #'foo
  '(and (number? %) (<= 0 %) (<= % 10)))
=> true

这是一个非常脆弱的平等测试。如果您重新排序and条件,则即使两个and在逻辑上相同,相等性测试也会失败。如果你愿意,你可以使测试更加健壮。

  

是否可以构造要参数化检验的后置条件?

是的,但这又会变得脆弱/受到上述相同的平等限制。在实践中,唯一的区别是我们需要将表单指定为一种模板并在将其传递给some-post?之前填入空白。我们可以定义一个函数,它将用我们想要的任何形式替换表单中的符号N

(defn parameterize-n [n form]
  (walk/postwalk #(if (= 'N %) n %) form))

(parameterize-n
  10
  '(and (number? %) (<= 0 %) (<= % N)))
=> (and (number? %) (<= 0 %) (<= % 10))

我们可以像some-post?这样使用它:

(some-post?
  #'foo
  (parameterize-n
    10
    '(and (number? %) (<= 0 %) (<= % N))))
=> true

顺便说一句,(<= 0 % 10)相当于(and (<= 0 %) (<= % 10)),但我逐字地使用了您的示例测试。