clojure.spec:序列规范的`alt` vs`或`

时间:2016-06-02 05:54:20

标签: clojure

我正在关注clojure.spec的指南(http://clojure.org/guides/spec)。我对序列规范altor之间的区别感到困惑。

对我来说,以下两个例子同样有效。那么这两者之间的区别是什么呢?

; Use `alt`
(s/def ::config (s/* (s/cat :prop string?
                        :val (s/alt :s string? :b boolean?))))
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])

; Use `or`
(s/def ::config (s/* (s/cat :prop string?
                        :val (s/or :s string? :b boolean?))))
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])

2 个答案:

答案 0 :(得分:12)

s/alt用于连接嵌套的正则表达式规范,其中使用s/or指定嵌套序列。在您的示例中,由于您没有使用嵌套的正则表达式规范,因此它没有任何区别。这是一个例子:

(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

如您所见,or指定了一个嵌套序列,其中启动了一个新的正则表达式上下文,而alt指定了相反的:

(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

答案 1 :(得分:8)

来自http://clojure.org/guides/spec,我们知道

  

当组合正则表达式操作时,它们描述单个序列。

这意味着如果你想要有效嵌套序列,你应该这样做。

(s/def ::config (s/* 
                 (s/cat :prop string?
                        :val (s/spec
                              (s/alt :s string? :b #(instance? Boolean %))))))

然后您的数据看起来像这样(注意括号左右)

(s/explain ::config ["-server" ["foo"] "-verbose" [true] "-user" [13]])

另外,如果你这样做(s /或)。

(s/def ::config (s/* (s/cat :prop string?
                            :val (s/spec 
                                  (s/or :s string? :b #(instance? Boolean %))))))

您的数据应与旧数据相同(注意周围没有括号)

(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])

BTW,对于非嵌套序列。 (s / alt)和(s /或)之间仍有一点点差异:

;;; 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]