What does the retag parameter mean in s / multi-spec?

Can you explain with examples how the retag parameter affects the creation of multi-spec ? I find the multi-spec documentation is hard to grasp.

+5
source share
1 answer

From docstring:

retag is used during generation to create generated values ​​using matching labels. The retag can be either a keyword in which the dispatcher-tag key will be associated, or fn of the generated value and a send tag, which should return a properly modified value.

If retag is a keyword (as in the specs example ), multi-spec internally creates a function here that is used in the generator's implementation function. For example, these two declarations with several specifications are functionally equivalent:

 (s/def :event/event (s/multi-spec event-type :event/type)) (s/def :event/event (s/multi-spec event-type (fn [genv tag] (assoc genv :event/type tag)))) 

Passing the retag function retag not seem like a very useful option given in the example manual, but more useful when using multi-spec for non-cards. For example, if you want to use multi-spec with s/cat , for example. in spec args function:

 (defmulti foo first) (defmethod foo :so/one [_] (s/cat :typ #{:so/one} :num number?)) (defmethod foo :so/range [_] (s/cat :typ #{:so/range} :lo number? :hi number?)) 

foo takes two or three arguments, depending on the first argument. If we try multi-spec naively use the keyword / s/cat tag, this will not work:

 (s/def :so/foo (s/multi-spec foo :typ)) (sgen/sample (s/gen :so/foo)) ;; ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.Associative 

It is useful to use the retag function retag :

 (s/def :so/foo (s/multi-spec foo (fn [genv _tag] genv))) (sgen/sample (s/gen :so/foo)) ;=> ;((:so/one -0.5) ; (:so/one -0.5) ; (:so/range -1 -2.0) ; (:so/one -1) ; (:so/one 2.0) ; (:so/range 1.875 -4) ; (:so/one -1) ; (:so/one 2.0) ; (:so/range 0 3) ; (:so/one 0.8125)) 
+4
source

Source: https://habr.com/ru/post/1270353/


All Articles