Как изобразить родительско-дочерние отношения между двумя записями / картами? - PullRequest
0 голосов
/ 30 октября 2019

Я пытаюсь представить элементы графического интерфейса в Clojure / Script. Проблема в том, что элементы являются вложенными и должны общаться друг с другом. Я думал передать ссылки друг другу, но, кажется, я не могу просто передать друг другу ссылки, как я наивно думал.

Код, который я пробовал

(defrecord Element [position size parent children state type value])
(def parent (atom (Element. ...)))
(def child  (atom (Element. ...)))
(assoc @parent :child child)
(assoc @child :parent parent)

это не работает.

Каково идиоматическое решение в Clojure для такого рода проблем?


Обновление: кажется, что взаимные ссылки не работают:

(defrecord Element [position size parent children state type value])

(def parent (atom (Element. {:x 0 :y 0} {:width 1600 :height 900} nil nil :collapsed :container nil)))

(def child (atom (Element. {:x 5 :y 5} {:width 100 :height 100} nil nil :collapsed :container nil)))

(swap! parent assoc :child child)
(swap! child assoc :parent parent)

#object[InternalError InternalError: too much recursion]
   cljs.core.PersistentArrayMap.prototype.cljs$core$ILookup$_lookup$arity$2 (jar
:file:/C:/Users/user/.m2/repository/org/clojure/clojurescript/1.10.520/clojuresc
ript-1.10.520.jar!/cljs/core.cljs:6811:10)

Возможно, вClojure вы не делаете взаимные ссылки?

1 Ответ

2 голосов
/ 30 октября 2019

Вы assoc отдаете родителя ребенку, но затем выбрасываете новое Element. Вам необходимо установить значение в атоме, используя reset! или swap!:

(swap! parent assoc :child child)  ; Equivalent to (swap! parent #(assoc % :child child))
(swap! child assoc :parent parent)

swap! аналогично update, ноон заменяет значение, хранящееся в atom.


Также обратите внимание, что вы дали полю имя children, но в своем примере вы ссылаетесь на него, используя :child. children предполагает наличие нескольких детей, поэтому я бы изменил его, чтобы он начинался как вектор вместо nil, а затем conj. Я бы также создал new-element помощник:

(defrecord Element [position size parent children state type value])

(defn new-element [position size]
  (->Element position size nil [] :collapsed :container nil))

(def parent (atom (new-element {:x 0 :y 0} {:width 1600 :height 900})))
(def child (atom (new-element {:x 5 :y 5} {:width 100 :height 100})))

(swap! parent update :children conj child)
(swap! child assoc :parent parent)

Чтобы устранить полученную ошибку, она отлично работает для меня в Clojure .

Если я печатаю parent и child после запуска приведенного выше кода, я получаю бесконечный вывод, потому что для печати родительского элемента вам нужно распечатать дочерний элемент, а для печати дочернего элемента вы должны распечатать родительский ... Это все еще работает для меня.

Убедитесь, что ошибка не возникает, потому что вы пытаетесь распечатать структуру в REPL.

Это также может быть ограничением Clojurescript,К сожалению, я не могу ответить за это, так как я не знаком с Cljs.

Я удалю свой ответ, если это окажется бесполезным.


Я тожеобратите внимание, что вложение атомов не является хорошей идеей. atom s - это действительно изменяемые контейнеры для хранения неизменяемых объектов. Может быть, чище иметь систему идентификаторов, и каждый родитель / ребенок должен иметь числовой идентификатор своего ребенка / родителя. Тогда у вас есть один атом для всей вашей программы. Атомы могут содержать карту ID-> element для удобства поиска.

...