2016-06-02 40 views
11

Sto seguendo la guida clojure.spec (http://clojure.org/guides/spec). Sono confuso dalla differenza tra alt e or per le specifiche di sequenza.clojure.spec: `alt` vs` or` per spec. Sequenza

Per me i due esempi seguenti funzionano altrettanto bene. Quindi qual è la differenza tra i due?

; 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]) 
+0

Una cosa da provare: scrivere uno spec usando 'o', poi mano a' spec/exercise' lo farà generare/convalidare 10 esempi per te. quindi passare a 'alt' e fare lo stesso. Io uso 'spec/exercise' tutto il tempo per il debug delle specifiche è fantastico confrontare quello che penso dovrebbe convalidare con l'output generato da una specifica buggy. –

risposta

9

s/alt è per concatenare le specifiche espressioni regolari nidificati in cui utilizzando s/or specifica una successione. Nel tuo esempio non fa differenza poiché non stai usando le specifiche regex annidate. Ecco un esempio:

(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 

Come si può vedere, or specifica un sub-sequenza in cui viene avviato un nuovo contesto regex, mentre alt specifica il contrario:

(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 
5

Da http://clojure.org/guides/spec, sappiamo

Quando le espressioni regex sono combinate, descrivono una singola sequenza.

che significa che se si desidera validare le sequenze nidificate, si dovrebbe fare così.

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

E poi i dati si presenta così (Avviso le parentesi intorno)

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

Inoltre, se si fa (s/o).

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

tuoi dati dovrebbe essere lo stesso di quello vecchio (Avviso non ci sono parentesi intorno)

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

BTW, per le sequenze non nidificate. c'è ancora una differenza po 'tra i (s/alt) e (s/o):

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