clojure.spec / unform返回不符合的值

时间:2016-08-25 13:54:28

标签: clojure clojurescript

我在clojure.spec上的表现非常好。但是,我遇到了一个问题,在处理unform时我无法解决这个问题。这是Hiccup让我们感动的一个松散的规范:

(require '[clojure.spec :as s])

(s/def ::hiccup
  (s/and
      vector?
      (s/cat
        :name       keyword?
        :attributes (s/? map?)
        :contents   (s/* ::contents))))

(s/def ::contents
  (s/or
    :element-seq (s/* ::hiccup)
    :element     ::hiccup
    :text        string?))

在我们被带走之前,让我们看看它是否适用于一个小案例。

(def example [:div])

(->> example
     (s/conform ::hiccup))

;;=> {:name :h1}

像魅力一样工作。但是,我们可以撤消我们的一致性吗?

(->> example
     (s/conform ::hiccup)
     (s/unform ::hiccup))

;;=> (:div)
嗯,那应该是一个载体。我错过了什么吗?让我们看一下规范对此有何看法。

(->> example
     (s/conform ::hiccup)
     (s/unform ::hiccup)
     (s/explain ::hiccup))

;; val: (:div) fails spec: :user/hiccup predicate: vector?
;;=> nil

确实,它失败了。所以问题是:如何使其正常工作?

2 个答案:

答案 0 :(得分:0)

为了什么是值得的,我做了一个规范,检查一个向量并解开向量:

(s/def ::hiccup
  (vector-spec
    (s/cat
      :name       keyword?
      :attributes (s/? map?)
      :contents   (s/* ::contents))))

在您的示例中,您可以像这样使用它:

Cert

答案 1 :(得分:0)

这里的最新回应。我没有意识到这个问题有多老,但是由于我已经写了答复,所以不妨提交它。

采用您为::hiccup提供的规范:

(s/def ::hiccup
  (s/and
      vector?
      (s/cat
        :name       keyword?
        :attributes (s/? map?)
        :contents   (s/* ::contents))))

vector?中的and规范将根据该谓词测试输入数据。不幸的是,它并没有变成矢量。

您可以采取的补救措施是添加一个中间规范,该规范将在合规时充当标识,在不合规时充当所需角色。例如

(s/def ::hiccup                                                                                                                                                                                           
  (s/and vector?                                                                                                                                                                                          
         (s/conformer vec vec)                                                                                                                                                                            
         (s/cat                                                                                                                                                                                           
          :name       keyword?                                                                                                                                                                            
          :attributes (s/? map?)                                                                                                                                                                          
          :contents   (s/* ::contents)))) 

(s/unform ::hiccup (s/conform ::hiccup [:div]))

;;=> [:div]

(s/conformer vec vec)对于满足vector?的所有内容都是禁忌,使用vec作为协调器中的不合格函数将确保结果对不合格{{1 }} spec仍然是向量。

我是自我介绍的新手,这就是我如何按照您的意图工作的。请记住,规范设计者可能不会使用它。