【发布时间】:2017-04-05 11:58:47
【问题描述】:
让我们从常规序列开始
(require '[clojure.spec :as spec]
'[clojure.spec.gen :as gen])
(spec/def ::cat (spec/cat :sym symbol? :str string? :kws (spec/* keyword?)))
匹配向量
(spec/conform ::cat '[af "5"])
=> {:sym af, :str "5"}
(spec/conform ::cat '[af "5" :key])
=> {:sym af, :str "5", :kws [:key]}
还有列表
(spec/conform ::cat '(af "5"))
=> {:sym af, :str "5"}
(spec/conform ::cat '(af "5" :key))
=> {:sym af, :str "5", :kws [:key]}
如果我们想限制这一点,我们可以尝试使用spec/tuple;但遗憾的是它只匹配固定长度的向量,即它至少需要一个空列表作为元组的最后一部分:
(spec/def ::tuple (spec/tuple symbol? string? (spec/* keyword?)))
(spec/conform ::tuple '[af "5"])
=> :clojure.spec/invalid
(spec/exercise ::tuple)
=> ([[r "" ()] [r "" []]] [[kE "" (:M)] [kE "" [:M]]] ...)
我们还可以尝试使用spec/and 向::cat 添加附加条件:
(spec/def ::and-cat
(spec/and vector? (spec/cat :sym symbol? :str string? :kws (spec/* keyword?))))
匹配的很好
(spec/conform ::and-cat '[af "5"])
=> {:sym af, :str "5"}
(spec/conform ::and-cat '[af "5" :key])
=> {:sym af, :str "5", :kws [:key]}
(spec/conform ::and-cat '(af "5" :key))
=> :clojure.spec/invalid
但遗憾的是无法生成自己的数据,因为 spec/cat 的生成器只生成当然不符合 vector? 谓词的列表:
(spec/exercise ::and-cat)
=> Couldn't satisfy such-that predicate after 100 tries.
总结一下:如何编写既能接受又能生成像[hi "there"][my "dear" :friend] 这样的向量的规范?
也可以将问题改写为“spec/cat 是否有替代方案可以生成向量而不是列表?”或“是否可以将 :kind 参数传递给spec/cat?”或“我可以将生成器附加到一个规范,该规范将原始生成器的输出转换为向量吗?”。
【问题讨论】:
标签: clojure clojure.spec