我有一个例子,我希望multimethod中的几个分派值映射到同一个方法。例如,对于分派值1,我希望它调用method-a,而对于分派值2、3或4,我希望它调用method-b。
在Googling搜索之后,我最终编写了以下宏:
(defmacro defmethod-dispatch-seq [mult-fn dispatch-values & body]
`(do (map
(fn [x#] (defmethod ~mult-fn x# ~@body))
~dispatch-values)))然后您可以像这样使用它:
(defmulti f identity)
(defmethod f 1 [x] (method-a x))
(defmethod-dispatch-seq f [2 3 4] [x] (method-b x))这使您可以调用以下内容:
(f 1) => (method-a 1)
(f 2) => (method-b 2)
(f 3) => (method-b 3)
(f 4) => (method-b 4)这是个好主意吗?
发布于 2015-03-10 19:32:23
我宁愿这样做:
(defn dispatch-function
[value]
(if (= 1 value) :case-a :case-b))
(defmulti f dispatch-function)
(defmethod f :case-a
[x]
:doing-something)
(defmethod f :case-b
[x]
:doing-something-else)这样就避免了宏,并将调度函数用于预期的目的。
发布于 2015-08-29 22:08:14
这实际上正是clojure中创建层次结构的目的。defmulti采用:hierarchy参数,该参数可以建立x is a y关系。
唯一的小问题是层次结构不能与数字一起工作。例如,你不能告诉它数字0“是”:a。然而,希望你真的只是为了简单而选择数字,并提出问题,并在实际案例中可能有关键字,你可以这样做:
(def hh (-> (make-hierarchy)
(derive :0 :a)
(derive :1 :a)
(derive :2 :b)
(derive :3 :b)
atom))
(isa? @hh :3 :b) ;; => true
(defmulti mm
"Demo of using hierarchy"
(comp keyword str)
:hierarchy hh)
(defmethod mm :b [orig] {:b orig})
(defmethod mm :a [orig] {:a orig})
(defmethod mm :default [orig] :oopsie)
(mm 2) ;; => {:b 2}
(mm 1) ;; => {:a 1}
(mm 4) ;; => :oopsie
;; Cool thing is we can steer this at RUNTIME!
(swap! hh derive :4 :b)
(mm 4) ;; => {:b 4}
;; So we can keep the data close to the definition:
(mapv #(swap! hh derive % :c) [:5 :6 :7])
(defmethod mm :c [orig] {:c orig})
(mm 6) ;; => {:c 6}备注:
(var hh),因为它与clojurescript一起工作得更好(cljs不喜欢vars in clojurescript)性能应该还不错。调度函数输出的所有内容都缓存了它解析到的实际方法的映射(遍历层次结构)。发布于 2015-03-10 18:58:09
因为这是一个未解决的问题(“这是个好主意吗?”)我将尝试解决脑海中浮现的两个问题:
defmethod并对它们使用相同的函数同样有效。因此,如果这是你的函数的行为方式,这看起来是一个好主意,但是你的函数以这种方式运行的事实可能表明你的模型中有一些缺陷:
在确保我的数据/函数应该如何工作之后,我会使用这样的分派机制。
https://stackoverflow.com/questions/28961343
复制相似问题