Clojure multimethod для класса ИЛИ ключевое слово - PullRequest
0 голосов
/ 23 марта 2011

Предположим, у меня есть этот мультиметод

(defmulti m (fn [v] [(:type v)]))

(defmethod m [Object] [k] (prn "Object"))

(defmethod m [:mykwd] [k] (prn "mykwd"))

Когда я вызываю его с подклассом Object, он корректно отправляется первой реализации:

(m {:type String})
"Object"

С :mykwd он также работает как ожидалось:

(m {:type :mykwd})
"mykwd"

Но когда я предоставляю другое ключевое слово, я получаю исключение:

(m {:type :anotherkwd})
#<CompilerException java.lang.IllegalArgumentException: No method in multimethod 'm'
for dispatch value: [:anotherkwd] (NO_SOURCE_FILE:0)>

Как именно эта отправка работает?

Можно ли сохранить это поведение для наследования классов и при этом иметь реализацию по умолчанию, которая перехватывает все ключевые слова?

EDIT Этот пример упрощен, но он мне нужен для работы с двоичными функциями. Моя настоящая потребность ниже. Я не понимаю, как я могу применить :default к нему.

(defmulti m (fn [arg mp] [(class arg) (:type mp)]))

Тогда я ищу способ определить его для случая, когда arg - это nil, а (:type mp) - что-нибудь. Это работает, когда значение для :type является классом, но не для любое ключевое слово :

(defmethod m [nil Object] [arg mp] (prn "Whatever"))

Ответы [ 2 ]

5 голосов
/ 23 марта 2011

Существует значение по умолчанию:

(defmethod m :default [x] :oops)

Ссылка:

Проверка http://clojure.org/multimethods внизу страницы.

2 голосов
/ 24 марта 2011

Попробуйте заменить отправку :type пользовательской функцией, которая возвращает значение по умолчанию, если :type равно nil. То же самое для class. Тогда вы можете отправить по вектору ключевых слов. Добавьте ключевые слова в иерархию, если вам нужно унаследованное поведение.

...