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
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))
source share