Что такое предикатная рассылка - PullRequest
25 голосов
/ 15 апреля 2011

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

Ответы [ 4 ]

22 голосов
/ 15 апреля 2011

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

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

15 голосов
/ 15 апреля 2011

Отредактировано: Мультиметоды Clojure не являются предикатной отправкой.

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

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

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

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

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

8 голосов
/ 16 апреля 2011

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

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

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

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

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

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

(fact 0)

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

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

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

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

2 голосов
/ 12 июля 2013

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

(defmulti my-method)

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

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

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

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

...