Протоколы Clojure - отправка только по 2-арной версии многоартериальной функции
Укороченная версия
Я хочу, чтобы многоартериальная функция отправляла тип для 2-арной версии, но я хочу, чтобы 1-арная версия была одинаковой для всех типов.
Длинная версия (с примером)
У меня есть протокол, который выглядит примерно так
(defprotocol foo
(bar [d] [d x]))
Если я хочу, чтобы "TypeA" расширил этот протокол, то у меня есть следующее
(extend-protocol foo
TypeA
(bar
([d] #(bar d %))
([d x] (TypeA-fn x))))
для некоторой функции TypeA-fn, специфичной для TypeA.
Если я хочу, чтобы "TypeB" расширил этот протокол, тогда у меня есть следующее
(extend-protocol foo
TypeB
(bar
([d] #(bar d %))
([d x] (TypeB-fn x))))
для некоторой функции TypeB-fn, специфичной для TypeB.
Эффект, который я пытаюсь создать, это эффект карри.
(bar instance-of-TypeA x)
это двойной, скажем, в то время как
(bar instance-of-TypeA)
возвращает функцию, которая отображает TypeA в double.
Дело в том, что реализация bar для единственной арности всегда одинакова, в то время как реализация для нескольких арностей зависит от типа. Естественно, я не хочу повторяться каждый раз, когда расширяю этот протокол для одноармейной версии, так что же это за идиоматический способ? Я решил не указывать одну версию Arity, а везде использовать (частичная панель TypeX), но я устал от частичной.
Предлагаемое решение я мог бы обернуть оригинальную функцию внутри новой функции, например
(defprotocol foo
(bar-method [d x]))
(extend-protocol foo
TypeA
(bar-method
([d x] (TypeA-fn x))))
(defn bar
([d] (fn [x] (bar-method d x))
([d x] (bar-method d x))
но введение двух функций для одной цели кажется неэлегичным.
1 ответ
Ваше предлагаемое решение именно то, что я бы предложил. Вы хотите функцию одного или двух аргументов; в случае с двумя аргументами вы хотите, чтобы он был полиморфным, поэтому имеет смысл для этого случая переслать что-то, что выполняет полиморфную диспетчеризацию.