defmethod поймать все - PullRequest
       33

defmethod поймать все

8 голосов
/ 25 февраля 2012

У меня есть мультиметод, который специализируется на двух параметрах:

(defmulti get-tag-type (fn [type tag] [type tag]))

Наличие типа позволяет мне группировать различные вызовы defmethod в наборы:

(defmethod get-tag-type [::cat 0] [type tag] ::tiger)
(defmethod get-tag-type [::cat 1] [type tag] ::lion)
(defmethod get-tag-type [::cat 2] [type tag] ::jaguar)

(defmethod get-tag-type [::dog 0] [type tag] ::poodle)
(defmethod get-tag-type [::dog 1] [type tag] ::australian-shepherd)
(defmethod get-tag-type [::dog 2] [type tag] ::labrador-retriever)

Однако иногда яхотите перехватить все или значение по умолчанию для одной из групп, которая будет вызвана, если ни одна из остальных не будет найдена:

(defmethod get-tag-type [::dog :default] ::mutt)

Однако это не будет работать, если tag на самом деле :default.

Какой хороший способ сделать это?

Ответы [ 3 ]

7 голосов
/ 25 февраля 2012

Ваша диспетчерская функция должна знать, какие отображения уже определены, чтобы она могла решить, когда прибегнуть к значению по умолчанию.Функция methods вернет вам эти сопоставления.

(defmulti get-tag-type (fn [type tag] 
                         (let [mlist (methods get-tag-type)]
                           (if-let [d (get mlist [type tag])] 
                             [type tag]
                             [type :default]))))
7 голосов
/ 25 февраля 2012

Мультиметоды поддерживают резервный метод, определяемый с помощью (настраиваемого) значения :default, если ни один из других методов не подходит.

В вашем случае вы просто добавили бы:

(defmethod get-tag-type :default [type tag]
  (do special behaviour here ...))

Учитывая ваш пример, возможно, стоит отметить, что вы можете устанавливать иерархии, используя ключевые слова Clojure, и диспетчер мультиметода понимает эти иерархии: http://clojure.org/multimethods

0 голосов
/ 25 февраля 2012

Вы можете изменить defmulti на:

(defmulti get-tag-type (fn [type tag] 
                         (if (= type ::dog)
                             ::dog
                             [type tag])))

Затем напишите свой метод так:

(defmethod get-tag-type ::dog ::mutt)
...