您能否举例说明retag参数如何影响multi-spec的创建?我发现multi-spec文档很难消化。
发布于 2017-10-09 15:30:43
从docstring:
retag是在生成过程中使用的,它可以用匹配的标记来恢复生成的值。retag可以是关键字,在关键字中调度标记将是assoc‘’ed,也可以是生成值和调度标记的fn,它们应该返回一个适当的重定位值。
如果retag是关键字(就像在规范指南示例中那样),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一起使用,例如用于规范函数args:
(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采用两个或三个arg,这取决于第一个arg。如果我们尝试使用multi-spec关键字/标记天真地使用s/cat,它将无法工作:
(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))发布于 2018-08-13 12:42:53
我同意医生们都很简洁!
我想要生成一个带有标记的multi-specd映射,该标记可以有几个值。我发现传递给retag函数的第二个参数实际上是调度标记,而不是指定的标记(回想起来,就像docs所说的那样)。这导致s/gen生成标记为(非默认) multimethod分派选项的映射,而不是标记规范覆盖的完整范围的映射。
(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很难解决,但还是值得的!
https://stackoverflow.com/questions/45394546
复制相似问题