clojure.spec: `alt` vs `or` for sequence spec

后端 未结 2 432
暗喜
暗喜 2021-01-01 15:54

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.

<
相关标签:
2条回答
  • 2021-01-01 16:40

    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]
    
    0 讨论(0)
  • 2021-01-01 16:46

    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
    
    0 讨论(0)
提交回复
热议问题