s/multi-spec 中的 retag 参数是什么意思?
What does retag parameter in s/multi-spec mean?
您能否举例说明 retag
参数如何影响 multi-spec
创建?我发现 multi-spec
文档难以理解。
来自文档字符串:
retag is used during generation to retag generated values with
matching tags. retag can either be a keyword, at which key the
dispatch-tag will be assoc'ed, or a fn of generated value and
dispatch-tag that should return an appropriately retagged value.
如果retag
是关键字(如生成器实现函数中使用的spec guide example), multi-spec
internally creates a function here。例如,这两个multi-spec声明在功能上是等价的:
(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))))
传递 retag
函数 似乎不是指南示例中非常有用的选项,但在将 multi-spec
用于非-地图。例如,如果您想将 multi-spec
与 s/cat
一起使用,例如指定函数参数:
(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
接受两个或三个参数,具体取决于第一个参数。如果我们尝试 multi-spec
天真地使用 s/cat
keyword/tag,它不会工作:
(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
这是能够传递 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))
我同意文档很简洁!
我想生成一个 multi-spec
d 地图,其中的标签可以有多个值。我发现传递给 retag
函数的第二个参数实际上是 dispatch 标签,而不是分配的标签(回想起来就像文档所说的那样)。这导致 s/gen
生成仅使用(非默认)多方法调度选项标记的地图,而不是标记规范涵盖的全部范围。
(s/def ::tag #{:a :b :c :d})
(s/def ::example-key keyword?)
(s/def ::different-key keyword?)
(defmulti tagmm :tag)
(defmethod tagmm :a [_]
(s/keys :req-un [::tag ::example-key]))
(defmethod tagmm :default [_] ; this is `defmulti`'s :default
(s/keys :req-un [::tag ::different-key]))
(s/def ::example (s/multi-spec tagmm :tag))
(gen/sample (s/gen ::example))
;=> only gives examples with {:tag :a, ...}
提供一个 retag
忽略它的第二个参数并返回生成的值使生成器按预期工作。
(s/def ::example (s/multi-spec tagmm (fn [gen-v tag] gen-v)))
;=> now gives examples from every ::tag
很难锻炼,但值得!
您能否举例说明 retag
参数如何影响 multi-spec
创建?我发现 multi-spec
文档难以理解。
来自文档字符串:
retag is used during generation to retag generated values with matching tags. retag can either be a keyword, at which key the dispatch-tag will be assoc'ed, or a fn of generated value and dispatch-tag that should return an appropriately retagged value.
如果retag
是关键字(如生成器实现函数中使用的spec guide example), multi-spec
internally creates a function here。例如,这两个multi-spec声明在功能上是等价的:
(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))))
传递 retag
函数 似乎不是指南示例中非常有用的选项,但在将 multi-spec
用于非-地图。例如,如果您想将 multi-spec
与 s/cat
一起使用,例如指定函数参数:
(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
接受两个或三个参数,具体取决于第一个参数。如果我们尝试 multi-spec
天真地使用 s/cat
keyword/tag,它不会工作:
(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
这是能够传递 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))
我同意文档很简洁!
我想生成一个 multi-spec
d 地图,其中的标签可以有多个值。我发现传递给 retag
函数的第二个参数实际上是 dispatch 标签,而不是分配的标签(回想起来就像文档所说的那样)。这导致 s/gen
生成仅使用(非默认)多方法调度选项标记的地图,而不是标记规范涵盖的全部范围。
(s/def ::tag #{:a :b :c :d})
(s/def ::example-key keyword?)
(s/def ::different-key keyword?)
(defmulti tagmm :tag)
(defmethod tagmm :a [_]
(s/keys :req-un [::tag ::example-key]))
(defmethod tagmm :default [_] ; this is `defmulti`'s :default
(s/keys :req-un [::tag ::different-key]))
(s/def ::example (s/multi-spec tagmm :tag))
(gen/sample (s/gen ::example))
;=> only gives examples with {:tag :a, ...}
提供一个 retag
忽略它的第二个参数并返回生成的值使生成器按预期工作。
(s/def ::example (s/multi-spec tagmm (fn [gen-v tag] gen-v)))
;=> now gives examples from every ::tag
很难锻炼,但值得!