我可以使用 Clojure 规范验证函数吗?

问题描述

我可以使用 Clojure 规范系统来定义函数签名并验证函数是否满足它们吗?

这里有一些我尝试过但没有成功的例子

(s/valid? (s/fspec :args string? :ret string?) identity) ;; false

(def nope identity)
(s/valid? (s/fspec :args string? :ret string?) nope) ;; false

(s/conform (s/fspec :args string? :ret string?) identity) ;; invalid

(defn strmap [s] {:pre [(s/valid? string? s)] :post [(s/valid? string? %)]} s)
(s/valid? (s/fspec :args string? :ret string?) strmap) ;; false

(s/fdef strmap :args string? :ret string?)
(s/valid? strmap strmap) ;; true

(s/def ::str-pred (s/fspec :args string? :ret boolean?))
(s/valid ::str-pred (fn [s] true)) ;; false

我知道 fdef,但我想要一些我可以创作的东西。例如,创建相关函数签名的映射。

解决方法

您可以使用 :args 访问函数的 :rets/get-spec 规范,然后进行验证:

user=> (require '[clojure.spec.alpha :as s])
nil
user=> (defn strmap [s] s)
#'user/strmap
user=> (s/fdef strmap :args string? :ret string?)
user/strmap
user=> (s/valid? (:args (s/get-spec `strmap)) "foo")
true
user=> (s/valid? (:args (s/get-spec `strmap)) :bar)
false

我在 re-find.web 中使用它。

,

事实证明规范确实处理函数,但它期望参数是一个元组。

id=31

匿名函数文字似乎存在一些问题。我可能对宏扩展有些误解。

(s/valid? (s/fspec :args (s/cat :arg1 string?) :ret string?) identity) ;; true!
(s/valid? (s/fspec :args (s/cat :arg1 string?) :ret string?) (fn [x] (str x "hi there"))) ;; true
(s/valid? (s/fspec :args (s/cat :arg1 string?) :ret string?) (fn [x] x)) ;; true

(s/valid? (s/fspec :args (s/cat :arg1 string?) :ret string?) (fn [x] 42)) ;; false
,

clojure.spec 的替代方案,malli 是一个数据驱动的架构库,它具有 support for function schemas

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...