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