Я разрабатываю сложную структуру данных в Clojure с несколькими подструктурами.
Я знаю, что захочу расширить эту структуру со временем и могу время от времени хотеть изменить внутреннюю структуру, не повреждая различных пользователей структуры данных (например, я могу хотеть изменить вектор в hashmap, добавить некоторую структуру индексации по причинам производительности или включить тип Java),
Мои существующие взгляды:
Я думаю, что это будет работать, хотя я волнуюсь, что это начинает быть похожим на слишком большое количество кода "связующего звена". Также это, вероятно, также отражает мое большее знакомство с объектно-ориентированными подходами.
Что рекомендуемый путь состоит в том, чтобы сделать это в Clojure?
Я думаю, что 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
в настоящее время не определяют никаких фабричных функций для вас, но вы, вероятно, должны сделать это сами. Проверка правильности идет внутри этих функций (и/или соответствующих тестов).
Более концептуально сложные операции, конечно, идеально подходят для протокольных функций, построенных на фундаменте get
и Co.
О, и посмотрите на gvec.clj
в исходниках Clojure для примера того, как может выглядеть серьезный код структуры данных, написанный с использованием deftype
. Сложность здесь иного рода, чем та, которую вы описали в вопросе, но, тем не менее, это один из немногих примеров программирования пользовательских структур данных в Clojure, доступных в настоящее время для публичного потребления (и это, конечно, код отличного качества).
Конечно, это только то, что подсказывает мне моя интуиция на данный момент. Я не уверен, что на данном этапе существует много устоявшихся идиом, учитывая, что deftype
еще не был выпущен и т.д. :-)