2016-09-30 2 views
2

Я хочу, чтобы иметь возможность использовать мульти-метод, клонировать его как отдельную переменную и добавлять к ней без изменения оригинала. Как это может быть сделано?Можно ли клонировать мультиметод?

(defmulti hello :type) 

(defmethod hello :a 
    [e] (assoc e :a 1)) 

(hello {:type :a}) 
=> {:type :a :a 1} 

;; my attempt at cloning 
(def world @#'hello) 

(defmethod world :b 
    [e] (assoc e :b 2)) 

(world {:type :b}) 
=> {:type :b :b 2} 

;; I want this to throw... but because `hello` and `world` 
;; are the same function, it still works 
(hello {:type :b}) 
=> {:type :b :b 2} 

ответ

2

Фигурные его, глядя на https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L1769-L1777:

(defn clone 
    [multi name] 
    (let [table (.getMethodTable multi) 
     clone (clojure.lang.MultiFn. name 
            (.dispatchFn multi) 
            (.defaultDispatchVal multi) 
            (.hierarchy multi)] 
    (doseq [[dispatch-val method] table] 
     (.addMethod clone dispatch-val method)) 
    clone)) 

---- обратно к первоначальному вопросу ----

(defmulti hello :type) 

(defmethod hello :a 
    [e] (assoc e :a 1)) 

(def world (clone hello "world")) 

(defmethod world :b 
    [e] (assoc e :b 2)) 

(world {:type :b}) 
=> {:type :b :b 2} 

(hello {:type :b}) 
=> (throws) 
Смежные вопросы