Как лучше всего интегрироваться с абстракциями clojure?
Я реализую упорядоченный набор в clojure, где я получаю элементы на основе их ранга. Это означает, что я могу получить 4-й элемент (в соответствии с порядком набора), 3-й или 7-й, все в логарифмическом времени.
Для того, чтобы моя новая структура данных была интегрирована с общими методами clojure (или "абстракциями"), такими как conj
, get
, nth
и т. д. Какой лучший способ сделать это:
- На самом деле реализовать
conj
например, в протоколе моего типа данных, или - Реализовать Rich Hickey's
clojure.lang.IPersistentSet
или какой-то интерфейс, как это.
Первый кажется проще, но также проще испортить семантику функции. Во-вторых, мне кажется, что я реализую интерфейс, который никогда не был частью публичного API, и фактические методы, связанные с этим интерфейсом (протоколом), до смешного отличаются. Например, кажется, что для реализации conj
с моим набором, я должен реализовать cons
метод clojure.lang.IPersistentSet
, который имеет другое имя. Кажется, есть немного документации о том, как все это работает, что создает большие трудности в реализации этого ранжированного набора.
Какой из них выбрать? Должен ли я реализовать свои собственные или методы clojure.lang
интерфейс? Если я должен сделать последнее, где находится какая-то хорошая документация, которая может помочь мне пройти через все?
РЕДАКТИРОВАТЬ: Я хочу пояснить, что я пытаюсь сделать набор, из которого вы можете извлечь любой элемент (или "удалить" его) в логарифмическом времени, указав ранг элемента (например, "дать мне 5-й элемент, г-н. задавать."). Насколько мне известно, такой набор еще не существует в ближайшем будущем.
1 ответ
Во-первых, я только что выпустил библиотеку с именем avl.clj, которая реализует постоянные отсортированные карты и наборы с поддержкой стандартного API Clojure (они являются заменой встроенных отсортированных коллекций), а также временные и логарифмические временные ранги. запросы (через clojure.core/nth
)1. Оба Clojure и ClojureScript поддерживаются; производительность на стороне Clojure в основном находится на одном уровне со встроенными вариантами в моем предварительном тестировании. Перейдите по ссылке выше, если вы хотите попробовать. Любые отчеты об опыте будут с благодарностью!
Что касается актуального вопроса: я боюсь, что не так много документации по внутренним интерфейсам Clojure, но, тем не менее, их реализация - единственный способ привести свои пользовательские структуры данных в соответствие со встроенными модулями. core.rrb-vector (который я написал и сейчас поддерживаю) использует этот подход, как и другие библиотеки Contrib, реализующие различные структуры данных. Это также то, что я сделал с avl.clj, а также sorted.clj (который в основном является портом ClojureScript отсортированных коллекций на основе красного черного дерева, перенесенных в Clojure). Все эти библиотеки, а также собственные Clojure gvec.clj
файл, который реализует векторы хранения примитивов, созданные clojure.core/vector-of
, может служить примером того, что участвует. (Хотя я должен сказать, что легко пропустить метод здесь и там...)
Ситуация намного проще в ClojureScript, где все основные протоколы определены в верхней части core.cljs
, так что вы можете просто посмотреть на список и выбрать те, которые имеют отношение к вашей структуре данных. Надеюсь, то же самое будет верно и в отношении Clojure в один прекрасный день.
1 Удаление по рангу (disj my-set (nth my-set 123))
теперь. Я мог бы предоставить прямую реализацию позже, если она окажется достаточной для производительности. (Я обязательно напишу один, чтобы проверить, если это так.)