Как лучше всего интегрироваться с абстракциями clojure?

Я реализую упорядоченный набор в clojure, где я получаю элементы на основе их ранга. Это означает, что я могу получить 4-й элемент (в соответствии с порядком набора), 3-й или 7-й, все в логарифмическом времени.

Для того, чтобы моя новая структура данных была интегрирована с общими методами clojure (или "абстракциями"), такими как conj, get, nthи т. д. Какой лучший способ сделать это:

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

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