Подтвердить что ты не робот

Clojure мультиметоды против протоколов

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

Являются ли протоколы заменяющими мультиметоды? Если нет, не могли бы вы привести мне пример, где я бы использовал multimethods вместо протоколов?

4b9b3361

Ответ 1

Мультиметоды более мощные и дорогие,

использовать протоколы, если они достаточны, но если вам нужно отправить на основе фазы луны, как видно из Марса, то вам лучше всего использовать несколько методов.

Существуют протоколы, позволяющие простым элементам оставаться простыми и предоставлять способ для clojure генерировать очень тот же байт-код, что и эквивалентная java. Похоже, что большинство людей используют протоколы большую часть времени. Я использую multimethods, когда мне нужно отправить более одного аргумента, хотя я должен признать, что это только один раз, и все иерархии isa используются еще реже (по мне). поэтому вкратце используйте Multimethods, когда вам это нужно

лучший пример В моей экспирации прямо в начале, в core.clj

Ответ 2

Протокол и мультиметоды являются взаимодополняющими и предназначены для немного разных вариантов использования.

  • Протоколы обеспечивают эффективную полиморфную отправку, основанную на типе первого аргумента. Поскольку он способен использовать некоторые очень эффективные функции JVM, протоколы дают вам лучшую производительность.
  • Мультиметоды позволяют очень гибкий полиморфизм, который может отправлять на основе любой функции аргументов метода. Мультиметоды медленнее, но очень гибки.

В общем, мой совет - использовать протоколы, если у вас нет конкретного случая, требующего многоточия.

В случае, когда вам понадобятся многоточия, это примерно следующее:

(defn balance-available? [amount balance] (> balance amount))

(defmulti withdraw balance-available?)

(defmethod withdraw true [amount balance] 
  (- balance amount))

(defmethod withdraw false [amount balance] 
  (throw (Error. "Insufficient balance available!")))

Обратите внимание, что вы не можете использовать протоколы здесь по обоим причинам:

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

Ответ 3

Как упоминает Артур, мультиметоды более мощные и дорогие. В самом деле, протоколы можно рассматривать как частный случай mutlimethods, где функция отправки class. Конечно, на самом деле это не так, поскольку протоколы - это нечто большее.

Если вам нужно отправить что-то отличное от класса первого аргумента, вам нужно будет использовать мультиметод или редизайн. Диспетчерский тип является хорошим вариантом для протоколов.

Ответ 4

Мне нравятся мультиметоды, когда вам не нужна иерархия классов. Например, если у вас есть база данных мультимедиа, и ваши записи похожи на {:media-type :video, :bytes ...}, то вы можете иметь мультимед

(defmulti make-grayscale :media-type)

Затем вы можете сделать различные

; in video.clj
(defmethod make-grayscale :video [record]
  (ffmpeg ... (:bytes record))

; in photo.clj
(defmethod make-grayscale :photo [record]
  (imagemagick ... (:bytes record))

Таким образом, вы можете избежать наличия центрального выражения cond, чтобы получить модульность классов. Но вам не нужно проходить всю эту шаблонную иерархию классов "оболочка", которая для меня - это проклятие, которое нужно оставить для мира Java. Мультиметоды - это просто функции и для меня больше clojuresque.