Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure s/multi spec中的retag参数是什么意思?_Clojure_Multimethod_Clojure.spec - Fatal编程技术网

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))
(注意限定关键字!)