Как переместить молнию в левый/правый узел в clojure?

Я пишу дерево (дерево решений бизнес-процессов) в структуре данных clojure.

(require clojure.zip :as z)

(z/vector-zip 
    [ :billed?  
        [:yes  
            [:check-bank-account] 
            [:check-cash] ] 
        [:send-out-email] ])

когда код проходит по первому узлу, он будет читать ключевое слово и выполнять определенные действия, результатом будет True или False, тогда я бы хотел, чтобы он прошел в узел left (True) или right (False).

Когда мой код начинается с корневого узла и вызывает некоторую функцию, связанную с :billed?, он возвращает True, как clojure может войти в узел :yes или узел :send-out-email? Я думал, что есть только z/down, а left или right только для братьев и сестер, а не для детей.

Большое спасибо за ваше время и ценю любые мысли


person Shawn Zhang    schedule 27.01.2019    source источник


Ответы (2)


Застежки-молнии проходят через структуру данных, отслеживая текущую позицию. Чтобы добраться до разных узлов, вы должны применить последовательность движений к одной и той же молнии. Когда застежка-молния создана, вы находитесь прямо над деревом:

(z/node tree)
=> [:billed? [:yes [:check-bank-account] [:check-cash]] [:send-out-email]]

Таким образом, вы можете спуститься в дерево с помощью z/down и использовать z/node, чтобы получить текущий узел из местоположения молнии:

(-> tree
    z/down
    z/node)
=> :billed?

Если вы идете по дереву сверху к какому-то узлу, вам, вероятно, понадобятся только z/down и z/right, поскольку при спуске в дочерний вектор вы окажетесь у самого левого дочернего элемента. Это легче представить, если вы разместите вектор в виде плоской линии и представьте, что z/right просто перемещаете курсор к следующему элементу и z/down перемещаете курсор внутри вектора.

(-> tree
    z/down
    z/right
    z/node)
=> [:yes [:check-bank-account] [:check-cash]]

(-> tree
    z/down
    z/right
    z/right
    z/node)
=> [:send-out-email]

Вот пример того, как вы можете пройтись по этому дереву, сравнив ключи с картой фактов:

(def tree
  (z/vector-zip
    [:billed?
     [:wire-funds?
      [:check-bank-account]
      [:check-cash]]
     [:send-out-email]]))

(defn facts->action [facts]
  (loop [curr (z/down tree)]
    (let [node (z/node curr)]
      (if-let [fact (find facts node)]
        (if (val fact)
          (recur (-> curr z/right z/down)) ;; descend "left"
          (recur (-> curr z/right z/right z/down))) ;; descend "right"
        node))))

(facts->action {:billed? false})
=> :send-out-email
(facts->action {:billed? true :wire-funds? true})
=> :check-bank-account
(facts->action {:billed? true :wire-funds? false})
=> :check-cash
person Taylor Wood    schedule 27.01.2019

Сцепите несколько движений молнии.

Вот пример:

(require '[clojure.zip :as z])

(def zipper (z/vector-zip
              [:billed?
               [:yes
                [:check-bank-account]
                [:check-cash]]
               [:send-out-email]]))

(println (-> zipper z/down z/right z/down z/node))
(println (-> zipper z/down z/right z/down z/right z/down z/node))
person exupero    schedule 27.01.2019