Какой протокол расширить для типа Trie?

Я пишу реализацию структуры данных Trie в Clojure и решил, что лучше всего использовать derecord для создания собственного типа, который может перегружать функции, работающие с коллекциями. Как мне определить имя протокола для расширения, чтобы я мог реализовать conj и другие подобные функции для моего нового типа Trie?


person dmh    schedule 17.01.2016    source источник


Ответы (1)


Если вы хотите реализовать новую структуру данных, вам нужно использовать deftype вместо defrecord, так как последний жестко определяет определенную реализацию поведения карты для результирующих типов.

Что касается clojure.core функций сбора, то большинство из них основано на интерфейсах, а не на протоколах. (Однако ClojureScript использует протоколы.) Самый простой способ обнаружить, какие интерфейсы могут иметь отношение к новой структуре данных, — это изучить аналогичные структуры данных, которые уже существуют:

;; all superclasses and interfaces of the class of {}, that is,
;; clojure.lang.PersistentArrayMap
(ancestors (class {}))

;; interfaces only
(filter #(.isInterface %) (ancestors (class {})))

Поскольку вы планируете реализовать три, я предполагаю, что вы хотите реализовать карту или набор. Если это так, data.avl реализует все соответствующие интерфейсы (и все соответствующие протоколы в версии ClojureScript). ) — вы могли бы взглянуть на источник.

person Michał Marczyk    schedule 17.01.2016
comment
Отлично, спасибо! Однако у меня возникла другая проблема: как мне определить имя и порядок аргументов функций для расширения? Например, я знаю, что empty? является частью установленного интерфейса, но в коде Java он отображается как empty. Кроме того, cons принимает последовательность в качестве второго аргумента, но при определении функций в протоколах список аргументов вместо этого ожидает this в качестве первого аргумента. Как мне обойти это? - person dmh; 17.01.2016
comment
Для интерфейсов clojure.lang вы можете посмотреть исходный код либо самого Clojure, либо библиотеки, которая реализует эти интерфейсы (например, вышеупомянутый data.avl). Для интерфейсов, предоставляемых JDK, имеет смысл прочитать Javadoc — вот страница о java.util.Map в JDK 8, другие легко найти в Google. Неважно, в каком порядке пользовательские функции принимают свои аргументы; вам нужно реализовать методы, объявленные в соответствующих интерфейсах, а функции из clojure.core позаботятся об их вызове. - person Michał Marczyk; 17.01.2016
comment
Кроме того, empty? не соответствует напрямую ни одному методу ни в одном встроенном интерфейсе. Вместо этого он состоит из not и seq — см. (source empty?). Вместо этого метод empty, объявленный clojure.lang.IPersistentCollection, соответствует функции clojure.core/empty — описание того, что она делает, см. в (doc empty). - person Michał Marczyk; 17.01.2016