【问题标题】:How to accept only ordered collections in spec如何仅接受规范中的有序集合
【发布时间】:2018-12-13 11:48:32
【问题描述】:

如何制作只接受顺序(即保留顺序)集合的规范?

例如

cljs.user=> (s/def ::path (s/+ number?))                                                                                                                                                                                 
:cljs.user/path
cljs.user=> (s/explain ::path [])                                                                                                                                                                                                                           
val: () fails spec: :cljs.user/path predicate: number?,  Insufficient input
:cljs.spec.alpha/spec  :cljs.user/path
:cljs.spec.alpha/value  [] 
cljs.user=> (s/explain ::path [1 2 3])                                                                                                                                                                                                                      
Success!

果然如此,但同时要注意顺序

cljs.user=> #{1 2 3}
#{1 3 2}
cljs.user=> (s/explain ::path #{1 2 3})                                                                                                                                                                                                                     
Success!

这似乎没有任何意义。所以第二个问题:

为什么规范中与序列相关的表达式(cat、*、+、?)接受破坏序列的集合?

UPD 我在原始问题中弄乱了顺序/有序的区别。清理了术语。

【问题讨论】:

  • + 表示 1..n(就像在正则表达式中一样)。这并不意味着任何顺序。您必须自己为此添加一个谓词。

标签: clojure clojurescript clojure.spec


【解决方案1】:

如何制定只接受保留顺序集合的规范?

有一个 clojure.core 谓词函数 sorted? 将为实现 Sorted 的集合返回 true。

(sorted? (sorted-map))
=> true

对于内容恰好已排序但未实现 Sorted 的集合,它不会返回 true:

(sorted? [1 2 3])
=> false

您可以在规范中使用任意谓词函数,因此您可以定义一个函数,为具有排序内容的集合返回 true:

(defn ordered? [coll]
  (or (empty? coll) (apply <= coll)))

(ordered? [1 2 3])
=> true

然后您可以使用s/and 将此谓词与您的正则表达式规范结合起来:

(s/def ::path (s/and (s/+ number?)
                     ordered?))

(s/explain ::path [1 2 3])
Success!
=> nil

(s/explain ::path #{1 2 3})
val: [1 3 2] fails spec: :playground.so/path predicate: ordered?
=> nil

【讨论】:

  • 有序不代表有序……
  • 我用了不好的措辞。我所说的有序不是指排序,而是保持顺序。
【解决方案2】:

序列的规范(正则表达式规范)不应匹配有序的,即 sequential 集合。这是一个已在当前版本的规范中修复的错误,请参阅 CLJ-2183

在 Clojure 1.10.0-RC5 中,结果符合预期:

(s/conform ::path [1 2 3])   ; => [1 2 3]
(s/conform ::path #{1 2 3})  ; => :clojure.spec.alpha/invalid

(s/explain ::path #{1 2 3})
;; #{1 3 2} - failed: (or (nil? %) (sequential? %)) spec: :user/path

您可以在最后一行看到正则表达式规范现在只匹配 sequential? 的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    相关资源
    最近更新 更多