Протоколы 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 ответ

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

Другие вопросы по тегам