Протоколы Clojure — отправка только в двухуровневой версии функции множественной арности.

Краткая версия

Я хочу, чтобы функция множественной арности выполняла отправку по типу для версии с 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 с двойным значением.

Дело в том, что реализация bar с одной арностью всегда одинакова, тогда как реализация с несколькими арностями зависит от типа. Естественно, я не хочу повторяться каждый раз, когда я расширяю этот протокол для версии с одинарной арностью, так что это идиоматический способ clojure сделать это. Я думал не указывать одну версию арности и везде использовать (частичный штрих 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))

но введение двух функций вместо одной кажется неэлегантным.


person Lindon    schedule 27.04.2017    source источник
comment
Вы рассматривали мультиметоды? Кроме того, иногда ничто не сравнится со старым добрым выражением (cond ...).   -  person Alan Thompson    schedule 27.04.2017


Ответы (1)


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

person amalloy    schedule 27.04.2017