首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >clojure.spec/unform返回不一致的值

clojure.spec/unform返回不一致的值
EN

Stack Overflow用户
提问于 2016-08-25 21:54:28
回答 2查看 286关注 0票数 5

在很大程度上,我和clojure.spec相处得很好。然而,我遇到了一个在处理unform时无法解决的问题。这里有一个松散的规范,让我们继续前进:

代码语言:javascript
复制
(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?))

现在,在我们忘乎所以之前,让我们看看它是否适用于一个小的通过案例。

代码语言:javascript
复制
(def example [:div])

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

;;=> {:name :h1}

就像一种护身符。但是,我们可以撤销我们的一致性吗?

代码语言:javascript
复制
(->> example
     (s/conform ::hiccup)
     (s/unform ::hiccup))

;;=> (:div)

嗯,那应该是一个向量。我是不是遗漏了什么?让我们看看spec对此有什么看法。

代码语言:javascript
复制
(->> example
     (s/conform ::hiccup)
     (s/unform ::hiccup)
     (s/explain ::hiccup))

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

事实上,它失败了。所以问题是:我怎样才能让它正确地工作?

EN

回答 2

Stack Overflow用户

发布于 2020-04-17 18:19:29

这里是延迟响应。我没有意识到这个问题有多老了,但既然我已经写了回复,我不妨提交它。

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

代码语言:javascript
复制
(s/def ::hiccup
  (s/and
      vector?
      (s/cat
        :name       keyword?
        :attributes (s/? map?)
        :contents   (s/* ::contents))))

and中的vector?规范将根据该谓词测试输入数据。不幸的是,正如您所经历的那样,它不会变形为向量。

为了解决这个问题,您可以添加一个中间规范,该规范在符合时将充当标识,而在不符合时将按照所需的方式运行。例如。

代码语言:javascript
复制
(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]

对于满足vector?的所有内容,(s/conformer vec vec)都将是无操作的,并且使用vec作为conformer中的不一致函数将确保取消对整个and规范的结果仍然是一个向量。

我刚开始规范自己,这就是我是如何让它按照你的意图工作的。请记住,它可能不是spec设计者打算使用的方式。

票数 1
EN

Stack Overflow用户

发布于 2017-02-20 23:29:33

为了更有价值,我制定了一个规范,用于检查向量并将其转换为向量:

代码语言:javascript
复制
(defn vector-spec
  "Create a spec that it is a vector and other conditions and unforms to a vector.

  Ex (vector-spec (s/spec ::binding-form))
     (vector-spec (s/* integer?))"
  [form]
  (let [s (s/spec (s/and vector? form))]
    (reify
      s/Specize
      (specize* [_] s)
      (specize* [_ _] s)

      s/Spec
      (conform* [_ x] (s/conform* s x))
      (unform* [_ x] (vec (s/unform* s x))) ;; <-- important
      (explain* [_ path via in x] (s/explain s path via in x))
      (gen*  [_ overrides path rmap] (s/gen* s overrides path rmap))
      (with-gen* [_ gfn] (s/with-gen s gfn))
      (describe* [_] (s/describe* s)))))

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

代码语言:javascript
复制
(s/def ::hiccup
  (vector-spec
    (s/cat
      :name       keyword?
      :attributes (s/? map?)
      :contents   (s/* ::contents))))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39147258

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档