问题
在Clojure中,可以使用ifn?检查变量是否代表一个函数。
我问自己,如果有办法检查var是否是具有某些后置(或预置)条件的函数。
奖励:是否可以构建要参数化检查的后置条件?
示例
假设foo
代表一个函数(即(ifn? foo)
返回true
)。
如何检查foo
是否有某个帖子条件,例如它返回0
和10
之间的数字。换句话说,我如何检查foo
是否具有以下后置条件?
{:post (and (number? %) (<= 0 %) (<= % 10))
加分:是否可以检查N
而不是10
,其中N
是我可以选择的参数?
{:post (and (number? %) (<= 0 %) (<= % 10))
背景
我是implementing Bloom-filter data structure,如果我可以验证哈希函数,那将是非常好的。 (即,它们是函数,仅返回Bloom过滤器中0
和bits
之间的数字。)
说明
我已经知道一些解决方法,例如比如将哈希函数包装在包含后置条件的其他函数中,或者取其位数的模数。虽然我感谢上述用例的任何进一步的解决方法,但请包括对主要问题的明确答案(即“是否可以检查函数是否具有某种后置条件?”)。 “不,这是不可能的”也是我当然可以接受的答案。
答案 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))
,但我逐字地使用了您的示例测试。