How can I make a spec that accepts only sequential (i.e. order-preserving) collections?
For example
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!
That's as expected, but in the same time, pay attention to the order
cljs.user=> #{1 2 3}
#{1 3 2}
cljs.user=> (s/explain ::path #{1 2 3})
Success!
And that doesn't appear to make any sense. So a secondary question:
Why sequence-related expressions (cat, *, +, ?) in spec accept sequence-breaking collections?
UPD I've messed up sequential/ordered distinction in original question. Cleaned up terminology.
Specs for sequences (regex specs) should not match ordered, that is sequential collections. This was a bug that has been fixed in current versions of spec, see CLJ-2183.
In Clojure 1.10.0-RC5 the results are as expected:
(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
You can see in the last line that regex specs now only match values that are sequential?
.