clojure spec fdef不工作-在传递递归定义时

clojure spec fdef不工作-在传递递归定义时,clojure,specifications,Clojure,Specifications,这是我的clojure规范,是为类似hiccup的语法编写的 (:require [clojure.spec.alpha :as s] [clojure.spec.test.alpha :as st] )) (s/def ::tag (s/and keyword? #(re-matches #":[a-z]+([0-9]+)?" (str %)))) (s/de

这是我的clojure规范,是为类似hiccup的语法编写的

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


(s/def ::tag (s/and
              keyword?
              #(re-matches #":[a-z]+([0-9]+)?"
                           (str  %))))

(s/def ::org-content (s/cat
                      :tag ::tag
                      :content (s/+ (s/or
                                     :str string?
                                     :content ::org-content
                                     ))))
我在这里写了一个简单的函数规范-

(s/fdef org-headers-h3
        :args (s/cat :contact ::org-content)
        :ret keyword?)

(defn org-headers-h3 [doc]
  (first doc))

(st/instrument `org-headers-h3)

(org-headers-h3 [:div [:h1 "d"]])
出现以下错误:

*Call to #'modcss2.parser/org-headers-h3 did not conform to spec:
   In: [0] val: [:div [:h1 "d"]] fails spec: :modcss2.parser/tag at:
   [:args :contact :tag] predicate: keyword?  :clojure.spec.alpha/spec
   #object[clojure.spec.alpha$regex_spec_impl$reify__1200 0x6613f384
   "clojure.spec.alpha$regex_spec_impl$reify__1200@6613f384"]
   :clojure.spec.alpha/value ([:div [:h1 "d"]])
   :clojure.spec.alpha/args ([:div [:h1 "d"]])
   :clojure.spec.alpha/failure :instrument*
在我看来,我传递错误类型的论点是错误的。 但我正在为下面的陈述而努力

(s/valid? ::org-content [:div [:h1 "d"]]) => true

一个
s/cat
在另一个内部并不意味着它们是嵌套的,它们只是连接在一起。这适用于所有正则表达式规范

(s/conform (s/cat :foo (s/cat :bar int?)) [1]) ;=> {:foo {:bar 1}}

(s/conform (s/cat :foo (s/cat :bar int?)) [[1]]) ;=> ::s/invalid
您的
:args
规范扩展为如下内容:
(s/cat:contact(s/cat:tag::tag,,,)

要嵌套它们,可以使用
s/spec

(s/conform (s/cat :foo (s/spec (s/cat :bar int?))) [[1]]) ;=> {:foo {:bar 1}}
所有正则表达式规范都是这样连接的。在这种情况下,使用
s/和
来检查它是否是一个向量,并将其设置为非正则表达式规范,这样它就可以正常嵌套

(s/conform (s/cat :foo (s/and vector? (s/cat :bar int?))) [[1]]) ;=> {:foo {:bar 1}}
因此,要解决您的问题:

(s/def ::org-content
  (s/and vector?
         (s/cat
          :tag ::tag
          :content (s/+ (s/or
                         :str string?
                         :content ::org-content)))))