使用 clojure.spec 指定应用程序函数

问题描述 投票:0回答:1

考虑以下类似

apply
的函数:

(defn apply [f v]
  (f v))

我想以这样的方式指定这个函数,使其返回值满足与

f
的返回值相同的规范。此外,我还想指定输入值
v
满足
f
的输入规范。

我尝试指定类似的内容如下:

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

这个规范非常宽松。我想做的是量化两个谓词

returned?
argument?
以进一步约束规范。

(s/fdef apply
  :args (s/cat :f (s/fspec :args (s/cat :v argument?) :ret returned?))
  :ret returned?)

其中

argument?
returned?
表示两个任意谓词。据我了解,这种类型的量化在
clojure.spec
中是不可能的。

更一般地,这种类型的行为可以使用任何参数类型系统自然地表达,包括 Java 的泛型。这也可以使用

clojure.spec
来指定吗?

clojure clojure.spec
1个回答
0
投票

您需要一些函数来确定输入参数的规格

f
。我不知道有任何这样的功能,所以这是一种可能性。是的,我知道,它很脏:

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

(defn find-fn-spec [f]
  (first
   (for [[fvar fns] (-> #'stest/instrumented-vars deref deref)
         :when (or (= f (:wrapped fns))
                   (= f (:raw fns)))]
     (#'s/reg-resolve! (symbol fvar)))))

然后你可以使用该函数来编写我称之为

my-apply
的其他函数的规范(核心中已经有一个函数
apply
):

(defn my-apply [f v]
  (f v))

(s/fdef my-apply
  :args (s/and (s/cat :f fn? :x any?)
               (fn [input]
                 (let [{:keys [f x]} input]
                   (s/conform (:args (find-fn-spec f)) [x]))))
  :ret any?
  :fn (fn [{:keys [args ret]}]
        (s/valid? (:ret (find-fn-spec (first args))) ret)))

但我不建议你这样做...

© www.soinside.com 2019 - 2024. All rights reserved.