Clojure 规范:如何将元组指定为函数参数?
Clojure Spec: How can I spec a tuple as a function argument?
我在 Clojure 中有一个函数接受 2 元素向量作为参数:
(defn influence [[school value]])
我想使用我已注册的现有规范为该函数的参数编写规范:
(s/fdef influence :args (s/cat :arg (s/cat :school ::school, :value ::value))
但是,这不起作用,嵌套的 s/cat
调用在顶层运行,并将 ::school
的规范应用于整个参数列表。还有一个名为 s/tuple
的函数,它可能建议您可以执行
(s/fdef ->influence :args (s/cat :influence (s/tuple ::school ::value)))
但这也行不通。规范似乎以某种方式混淆并尝试使 规范名称 符合规范:
val: :my.ns/school fails spec: :my.ns/school at: [:args :school] predicate...
您可以像这样使用 2 个参数的常规函数开始:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]
))
(defn name-age
[name age]
(format "name=%s age=%d" name age))
(s/fdef name-age
:args (s/cat
:name string?
:age pos-int? ) )
(dotest
(spyx (name-age "joe" 42))
(stest/instrument `name-age)
(throws? (spyx (name-age "jill" :24))))
结果
(name-age ["joe" 42]) => "name=joe age=42"
然后将其重写为 1 个 arg 的 fn,即一个元组:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest] ))
(s/def ::name string?)
(s/def ::age pos-int?)
(s/def ::na-tup (s/cat :name-arg ::name :age-arg ::age))
(defn name-age
[na-tup]
(s/valid? ::na-tup na-tup)
(let [[name age] na-tup]
(s/valid? ::name name)
(s/valid? ::age age)
(format "name=%s age=%d" name age)))
(s/fdef name-age
:args (s/cat
:name ::name
:age ::age ) )
(dotest
(spyx (name-age ["joe" 42]))
(stest/instrument `name-age)
(throws? (spyx (name-age ["jill" :24]))) )
如果需要,您还可以获得一些帮助来解构 name-age
函数中的数据:
(s/conform ::na-tup na-tup) =>
{:name-arg "joe", :age-arg 42}
实时代码示例
我研究了 Clojure 规范文档并将它们变成了 may be seen here 的实时单元。可能会在某个时候将它们分解成一个单独的回购协议。
我在 Clojure 中有一个函数接受 2 元素向量作为参数:
(defn influence [[school value]])
我想使用我已注册的现有规范为该函数的参数编写规范:
(s/fdef influence :args (s/cat :arg (s/cat :school ::school, :value ::value))
但是,这不起作用,嵌套的 s/cat
调用在顶层运行,并将 ::school
的规范应用于整个参数列表。还有一个名为 s/tuple
的函数,它可能建议您可以执行
(s/fdef ->influence :args (s/cat :influence (s/tuple ::school ::value)))
但这也行不通。规范似乎以某种方式混淆并尝试使 规范名称 符合规范:
val: :my.ns/school fails spec: :my.ns/school at: [:args :school] predicate...
您可以像这样使用 2 个参数的常规函数开始:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]
))
(defn name-age
[name age]
(format "name=%s age=%d" name age))
(s/fdef name-age
:args (s/cat
:name string?
:age pos-int? ) )
(dotest
(spyx (name-age "joe" 42))
(stest/instrument `name-age)
(throws? (spyx (name-age "jill" :24))))
结果
(name-age ["joe" 42]) => "name=joe age=42"
然后将其重写为 1 个 arg 的 fn,即一个元组:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest] ))
(s/def ::name string?)
(s/def ::age pos-int?)
(s/def ::na-tup (s/cat :name-arg ::name :age-arg ::age))
(defn name-age
[na-tup]
(s/valid? ::na-tup na-tup)
(let [[name age] na-tup]
(s/valid? ::name name)
(s/valid? ::age age)
(format "name=%s age=%d" name age)))
(s/fdef name-age
:args (s/cat
:name ::name
:age ::age ) )
(dotest
(spyx (name-age ["joe" 42]))
(stest/instrument `name-age)
(throws? (spyx (name-age ["jill" :24]))) )
如果需要,您还可以获得一些帮助来解构 name-age
函数中的数据:
(s/conform ::na-tup na-tup) =>
{:name-arg "joe", :age-arg 42}
实时代码示例
我研究了 Clojure 规范文档并将它们变成了 may be seen here 的实时单元。可能会在某个时候将它们分解成一个单独的回购协议。