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

Что такое Predicate Dispatch

В последнее время я много говорил о отправке предикатов в Clojure и задаюсь вопросом, есть ли что-то в этом. Другими словами, что такое предикатная отправка и как она отличается от общих функций, полиморфизма ООП и шаблонов? Спасибо вам

4b9b3361

Ответ 1

В традиционном объектно-ориентированном программировании полиморфизм означает, что вы можете иметь несколько реализаций метода, а точная реализация, которая вызывается, определяется типом объекта, на который вы вызвали метод. Это отправка типа.

Отправка предикатов расширяет это, так что реализация метода, который вызывается, может быть определена чем угодно, включая другую произвольную функцию. Clojure предоставляет эту функцию в виде нескольких методов. В форме Clojure (defmulti name f) функция f - это функция отправки.

Функция отправки может быть class, и в этом случае вы вернетесь к отправке типа. Но эта функция может быть чем-то еще: вычисление ценности отправки, поиск материала в базе данных, даже вызов веб-службы.

Общая функция - это термин от других Lisps. Например, общий Lisp предоставляет общие функции, которые могут отправлять по типу и ограниченному набору других функций.

Ответ 2

Отправка предикатов включает в себя общие функции, полиморфизм ООП, сопоставление образцов и многое другое. Хороший обзор Передача предикатов: единая теория отправки Майкла Эрнста, Крейга Каплана и Крейга Чамберса. Из его тезисов:

Передача предикатов обобщает предыдущие механизмы отправки метода, позволяя произвольным предикатам управлять применимостью метода и используя логическую импликацию между предикатами в качестве переопределяющего отношения. Метод, выбранный для обработки отправки сообщения, может зависеть не только от классов аргументов, как в обычной объектно-ориентированной диспетчеризации, но также от классов подкомпонентов, состояния аргумента и отношений между объектами.

Ответ 3

Отправка предикатов - это способ предоставления различных ответов на вызов функции, основанный на числе, "форме" и значениях аргументов функции. Clojure функции уже отправляются в разные тела кода, в зависимости от количества аргументов, переданных функции:

(defn my-func
  ([a] (* a a))
  ([a b] (* a b)))

Clojure multimethods добавляют к этому возможность отправлять разные методы - возможно, определенные в разных пространствах имен - на основе возвращаемого значения функции отправки, которая анализирует аргументы (которые могут включать их число, класс и значение) и определяет, какой метод для всех. Как отмечено в сносках к ответу Стюарта Сьерра, создатель мультиметода получает определение функции отправки, и его обычно нельзя изменять. Кроме того, программист должен вручную сконструировать сверхкомплексную функцию отправки для функции, которая выполняет одну вещь для целого числа 0, а другая для положительного целого; или одно для списка одного или нескольких элементов, а другое для пустого списка.

Отправка предикатов (возможно) обеспечит синтаксис, создающий эту сложную функцию отправки. Например, факториальную функцию можно определить таким образом

(defmatch fact [0] 1)
(defmatch fact [n] (* n (fact (dec n))))

Предыдущий код отвечает на вызов

(fact 0)

последний код для вызова с единственным аргументом любого другого значения. Это (за кулисами) определяет мультиметод с функцией отправки, которая отличает ноль от других значений.

Но позже я мог указать, что я хочу факториал для карты (возможно) путем кодирования

(defmatch fact [x {}] (fact (:value x)))

и код мог (теоретически) перехватывать вызовы, передавая карту факту, делегируя другие вызовы исходной функции отправки... все за кулисами.

Ответ 4

Чтобы сопоставить отправку предикатов с помощью нескольких методов, это немного похоже на то, что вы определили мультиметод без указания отправки fn:

(defmulti my-method)

и, если вы хотите его расширить, вы не укажете значение отправки (поскольку для его создания не требуется разгон fn), но предикат:

(defmethod my-method (fn [a b] (and (vector? a) (vector? b)))
  [a b]
  (do something))

Простой и мощный.

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