2013-09-20 4 views
3

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

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

  1. На самом деле реализуйте conj, например, в моем протоколе типа данных, или
  2. Внесите богатый Хикки clojure.lang.IPersistentSet или какой-нибудь интерфейс.

Первое кажется проще, но также проще испортить семантику функции. Во-вторых, похоже, что я реализую интерфейс, который никогда не должен был быть частью публичного API, а фактические методы, связанные с этим интерфейсом (протоколом), смешиваются по-разному. Например, кажется, что для того, чтобы реализовать conj с моим набором, я должен реализовать метод consclojure.lang.IPersistentSet, который имеет другое имя. Кажется, у вас мало документации о том, как все это работает, что создает большую проблему при реализации этого ранжированного набора.

Какой из них выбрать? Должен ли я реализовать свои собственные или методы интерфейса clojure.lang? Если я буду делать последнее, где есть хорошая документация, которая может помочь мне через разводы?

EDIT: Я хочу, чтобы понять, что я пытаюсь сделать набор, из которого вы можете получить любой элемент (или «удалить» его) в логарифмическое время, указав ранга элемента (например, " дайте мне 5-й элемент, mr. set. "). Насколько мне известно, такой набор еще не существует в clojure.

ответ

4

Во-первых, я только что выпустил библиотеку под названием avl.clj, которая реализует постоянные сортированные карты и наборы с поддержкой стандартного API Clojure (они являются заменами для встроенных отсортированных коллекций), а также переходных процессов и логарифмических (через clojure.core/nth) . Поддерживаются как Clojure, так и ClojureScript; производительность на стороне Clojure в основном наравне со встроенными вариантами в моем предварительном бенчмаркинге. Следуйте приведенной ссылке, если вы хотите попробовать. Любые отчеты об опыте будут очень признательны!

Что касается актуального вопроса: я боюсь, что документации по внутренним интерфейсам Clojure мало, но при этом их реализация - единственный способ сделать свои пользовательские структуры данных подходящими для встроенных интерфейсов, дюймы core.rrb-vector (который я написал и теперь поддерживаю) использует этот подход, как и другие библиотеки Contrib, реализующие различные структуры данных. Это также то, что я сделал с avl.clj, а также sorted.clj (в основном это порт ClojureScript сортированных коллекций с красно-черным деревом, переданных в Clojure). Все эти библиотеки, а также собственный файл gvec.clj Clojure, который реализует векторы примитивного хранения, созданные clojure.core/vector-of, могут служить примерами того, что задействовано. (Хотя я должен сказать, что легко пропустить метод здесь и там ...)

В ClojureScript ситуация намного проще, где все основные протоколы определены в верхней части core.cljs, поэтому вы можете просто взглянуть на список и выберите те, которые относятся к вашей структуре данных. Надеюсь, то же самое произойдет и на стороне Clojure.


Удаление от ранга (disj my-set (nth my-set 123)) сейчас. Я мог бы обеспечить прямую реализацию позже, если окажется, что она будет достаточно разной по производительности. (Я обязательно напишу, чтобы проверить, не делает ли это.)

+0

Начиная с версии 0.0.3 карты avl.clj однозначно бывают быстрее для поиска, чем встроенные сортированные карты, и предлагают значительно более быстрое построение больших экземпляров благодаря переходные процессы. Одиночный (непереходный) 'assoc' /' dissoc' медленнее - это затраты на быстрый поиск. –

+0

Как в стороне, почему вы решили использовать дерево AVL над красно-черным деревом? – djhaskin987

+0

@ djhaskin987 Из-за их алгоритмических свойств - деревья AVL предлагают значительно более быстрый поиск за счет более медленных вложений/удалений. Временная поддержка - это способ сделать эти более медленные операции «обновления» приемлемыми в типичных сценариях, связанных с несколькими обновлениями соседних частей дерева. (Разумеется, это компромисс между пространством и временем). –