Clojure s/multi spec中的retag参数是什么意思?
您能否举例说明Clojure s/multi spec中的retag参数是什么意思?,clojure,multimethod,clojure.spec,Clojure,Multimethod,Clojure.spec,您能否举例说明retag参数如何影响multi-spec创建?我发现多规范文档很难理解。来自文档字符串: 在生成过程中使用retag来重新标记生成的值 匹配标签。retag可以是关键字,在该关键字处 将关联分派标签,或生成值的fn和 应返回适当重新标记值的分派标记 如果retag是一个关键字(如中所示),multi-spec在内部创建一个用于生成器实现函数的函数。例如,这两个多规范声明在功能上是等效的: (s/def :event/event (s/multi-spec event-type :
retag
参数如何影响multi-spec
创建?我发现多规范
文档很难理解。来自文档字符串:
在生成过程中使用retag来重新标记生成的值
匹配标签。retag可以是关键字,在该关键字处
将关联分派标签,或生成值的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
时更有用。例如,如果要将多规范
与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
接受两个或三个参数,具体取决于第一个参数。如果我们天真地使用s/cat
关键字/标记尝试multi-spec
,它将不起作用:
(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))
我同意这些文件很简洁 我想生成一个带有标记的
多规范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
努力工作,但值得 感谢您的精彩解释和示例!我认为如果你有(s/def::tag关键字?
,那么你可以有(s/def::example(s/multi-spec tagmm::tag))
(注意限定关键字!)