2012-12-14 1 views
1

Как создать несколько реализаций мультиметода для одного типа данных?Возможно ли предусмотреть несколько различных реализаций многомерного метода для одного и того же типа?

Это не может быть отличным примером, но я надеюсь, что это иллюстрирует мысль: быть в состоянии обработать вложенные векторы как в последовательности:

repl> (def thing [[[1] []] [27] [18 [32 35]]]) 

repl> (fmap count thing) 
[2 1 2] 

и как деревья:

repl> (fmap (partial + 1) thing) 
[[[2] []] [28] [19 [33 36]]] 

Что такое общий способ создания и использования нескольких реализаций нескольких меток для одного и того же типа?

+0

Я не думаю, что здесь используются многометоды - 'defmethod' заменяет любой предыдущий метод, определенный для этого значения отправки, с новым. – Alex

+0

Если функции выполняют две совершенно разные вещи, почему бы просто не объявить две разные функции/мультиметоды? – DaoWen

+0

Мультиметоды являются полиморфными во всем, а не только по типу (хотя это наиболее распространено). Таким образом, если у вас есть способ различать объекты одного типа, которые вы хотите обрабатывать одним способом, и объекты того же типа, которые вы хотите обработать другим, это нормально. –

ответ

0

Идея мультиметодов заключается в том, что вы выполняете «ту же операцию» на «разных аргументах» (и не обязательно на разных типах). Если вы хотите выполнить «другую операцию» в «тех же аргументах», то мульти-методы не подходят, и, как и предлагаемое @DaoWen, просто использование отдельных функций (или даже отдельных мульти-методов), вероятно, является правильным способом пойдите об этом.

Если у вас есть какой-то способ программно отличить аргументы, и он делает концептуальный смысл использовать разные реализации методов на основе этих отличительных характеристик, тогда вы можете использовать аргумент dispatch-fn, чтобы сделать различие.

В качестве простого примера вы можете использовать ключ: foo как dispatch-fn, который будет отправлять на значение, связанное с ключом: foo на карте, которая передается в качестве единственного аргумента вашему мульти-методу.

+0

Спасибо за ответ! Тем не менее, я не могу просто использовать другую операцию - что бы победить всю точку абстракции Functor! Я попробую 'dispatch-fn' и посмотрю, как это работает. Спасибо за предложение! –

1

В вашей проблеме вам нужно отправить параметр типа fmap first arg. AFAIK нет (простой?) Способ определить тип аргумента любых функций (исправьте меня, если это не так). Поэтому вы должны добавить это как некоторые метаданные в параметр или что-то в этом роде. Например,

(defmulti fmap (fn [f _] ((comp :arg-seq? meta) f))) 

(defmethod fmap true [f col] 
    (map-tree f col)) 

(defmethod fmap false [f col] 
    (map f col)) 

(fmap (with-meta inc {:arg-seq? true}) thing) 
-> [[[2] []] [28] [19 [33 36]]] 

(fmap (with-meta count {:arg-seq? false}) thing) 
-> (2 1 2) 

Но это выглядит не очень хорошо. Если есть другой способ получить тип параметра функции, тогда решение может быть более приятным.

+0

Интересное предложение, спасибо. –