Логически невозможно сделать циклически чистые неизменяемые структуры, поскольку при добавлении родительского или дочернего указателя вы изменили бы структуру.
Существует способ, который работает, хотя я не уверен, что рекомендуюэто: вы можете поместить атомы в структуры данных Clojure, а затем изменить их, чтобы получить необходимые ссылки.например,
(def parent {:id 1 :children (atom nil) :parent (atom nil)})
(def child {:id 2 :children (atom nil) :parent (atom nil)})
(swap! (:children parent) conj child)
(reset! (:parent child) parent)
;; test it works
(:id @(:parent child))
=> 1
Это неприятно во всех отношениях:
- Это приведет к переполнению стека в вашем REPL, если вы попытаетесь распечатать один из них, потому что REPL не являетсяожидая циклические структуры данных.
- Это изменчиво, поэтому вы теряете все преимущества удобства поддержки и параллелизма неизменяемых структур данных (что является одной из самых приятных вещей в Clojure!)
- Вам понадобитсявзять полную копию узла, если вы хотите продублировать его (например, создать новый документ XML), так как это больше не является неизменным значением.
- Разыменование всех атомов может стать грязным при навигацииструктура.
- Вы будете путать людей, которые привыкли к идиоматической Clojure.
Итак, это возможно, если вы действительно хотите это сделать ........хотя лично я думаю, что в конечном итоге вам будет намного лучше, если вы сделаете свое представление документа должным образом неизменным.Возможно, вы могли бы использовать что-то более похожее на расположение в стиле XPath в документе, если вы хотите перемещаться по структуре.