I\'m following clojure.spec\'s guide (http://clojure.org/guides/spec). I\'m confused by the difference between alt
and or
for sequence spec.
From http://clojure.org/guides/spec, we know
When regex ops are combined, they describe a single sequence.
that means if you want to valid the nested sequences, you should do like this.
(s/def ::config (s/*
(s/cat :prop string?
:val (s/spec
(s/alt :s string? :b #(instance? Boolean %))))))
And then your data looks like this (Notice the brackets around)
(s/explain ::config ["-server" ["foo"] "-verbose" [true] "-user" [13]])
Also, if you do (s/or).
(s/def ::config (s/* (s/cat :prop string?
:val (s/spec
(s/or :s string? :b #(instance? Boolean %))))))
your data should be the same as the old one (Notice there are no brackets around)
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])
BTW, for non-nested sequences. there is still a little bit difference between (s/alt ) and (s/or):
;;; for (s/or)
(s/def ::name-or-id (s/or :name string?
:id int?))
(s/conform ::name-or-id 42) ;;=> [:id 42]
;;; for (s/alt)
(s/def ::name-or-id (s/alt :name string?
:id int?))
(s/conform ::name-or-id [42]) ;;=> [:id 42]
s/alt
is for concatenating nested regex specs where using s/or
specifies a nested sequence. In your example it doesn't make a difference since you are not using nested regex specs. Here is an example:
(s/def ::number-regex (s/* number?))
(s/def ::or-example (s/cat :nums (s/or :numbers ::number-regex)))
(s/valid? ::or-example [1 2 3])
;;-> false
(s/valid? ::or-example [[1 2 3]])
;;-> true
As you can see, or
specifies a nested sequence in which a new regex context is started, whereas alt
specifies the opposite:
(s/def ::alt-example (s/cat :nums (s/alt :numbers ::number-regex)))
(s/valid? ::alt-example [1 2 3])
;;-> true
(s/valid? ::alt-example [[1 2 3]])
;;-> false