Абстрагирование от деталей реализации структуры данных в Clojure - PullRequest
14 голосов
/ 24 июня 2010

Я разрабатываю сложную структуру данных в Clojure с несколькими подструктурами.

Я знаю, что я захочу расширить эту структуру с течением времени, и, возможно, иногда захочу изменить внутреннюю структуру, не нарушая различных пользователей структуры данных (например, я могу захотеть изменить вектор в hashmapдобавить некоторую структуру индексации по соображениям производительности или включить тип Java)

В настоящее время я думаю:

  • Определение протокола для всей структуры с помощью различных методов доступа
  • Создание мини-библиотеки функций для навигации по структуре данных, например (query-substructure-abc param1 param2)
  • Реализация структуры данных с использованием defrecord или deftype, с методами протокола, определенными для использования мини-library

Я думаю, что это будет работать, хотя я волнуюсь, что это начинает выглядеть как довольно много "склеивающего" кода.Также это, вероятно, также отражает мое большее знакомство с объектно-ориентированными подходами.

Каков рекомендуемый способ сделать это в Clojure?

1 Ответ

11 голосов
/ 24 июня 2010

Я думаю, что deftype может быть подходящим вариантом, однако я бы хотел воспользоваться методами доступа. Вместо этого посмотрите на clojure.lang.ILookup и clojure.lang.Associative; это интерфейсы, которые, если вы реализуете их для своего типа, позволят вам использовать get / get-in и assoc / assoc-in, что делает их гораздо более универсальным решением (не только вы сможете изменить базовая реализация, но, возможно, также использовать функции, созданные поверх стандартной библиотеки коллекций Clojure, для управления вашими структурами).

Несколько замечаний:

  1. Вы, вероятно, должны начать с defrecord, используя get, assoc & Co. со стандартными defrecord реализациями ILookup, Associative, IPersistentMap и java.util.Map. Возможно, вам удастся пройти довольно долгий путь.

    Если / когда этого уже недостаточно, взгляните на источники для emit-defrecord (закрытая функция, определенная в core_deftype.clj в источниках Clojure). Это довольно сложно, но даст вам представление о том, что вам может понадобиться реализовать.

  2. Ни deftype, ни defrecord в настоящее время не определяют какие-либо заводские функции для вас, но вам, вероятно, следует сделать это самостоятельно. Проверка работоспособности выполняется внутри этих функций (и / или соответствующих тестов).

  3. Более концептуально сложные операции, безусловно, идеально подходят для протокольных функций, построенных на основе get & Co.

Да, и посмотрите на gvec.clj в источниках Clojure для примера того, как может выглядеть какой-то серьезный код структуры данных, написанный с использованием deftype. Сложность здесь отличается от того, что вы описываете в этом вопросе, но все же это один из немногих примеров программирования пользовательских структур данных в Clojure, доступных в настоящее время для общего пользования (и, конечно, это код отличного качества).

Конечно, это именно то, что говорит мне моя интуиция в это время. Я не уверен, что на данном этапе есть много способов установить идиомы, что с deftype на самом деле не было выпущено и все. : -)

...