Отсчет от деталей реализации структуры данных в Clojure

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

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

Мое современное мышление:

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

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

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

Ответы

Ответ 1

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

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

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

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

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

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

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

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