如何为 `'(foo (:x 1 :y 2))` 定义 Clojure 规范

How to define Clojure spec for `'(foo (:x 1 :y 2))`

那个:

(s/def ::a (s/cat :k keyword? :i int?))
(s/def ::b (s/cat :symbol any?
                  :a      (s/coll-of ::a)))

规格: (s/conform ::b '(foo ((:x 1) (:y 2))))

那个:

(s/def ::a (s/cat :k keyword? :i int?))
(s/def ::b (s/cat :symbol any?
                  :a      (s/* ::a)))

规格: (s/conform ::b '(foo :x 1 :y 2))

但是我该如何指定 (s/conform ::b '(foo (:x 1 :y 2)))

要将其嵌套到列表中,您需要将其包装在 s/spec 中。例如:

(s/def ::b (s/cat :symbol any? :a (s/spec (s/* ::a))))

这个在Spec Guide中提到:

When regex ops are combined, they describe a single sequence. If you need to spec a nested sequential collection, you must use an explicit call to spec to start a new nested regex context. For example to describe a sequence like [:names ["a" "b"] :nums [1 2 3]], you need nested regular expressions to describe the inner sequential data:

 (s/def ::nested
   (s/cat :names-kw #{:names}
          :names (s/spec (s/* string?))
          :nums-kw #{:nums}
          :nums (s/spec (s/* number?))))
 (s/conform ::nested [:names ["a" "b"] :nums [1 2 3]])
 ;;=> {:names-kw :names, :names ["a" "b"], :nums-kw :nums, :nums [1 2 3]}