Молнии проходят через структуру данных, отслеживая текущую позицию. Чтобы добраться до разных узлов, вы должны применить последовательность ходов к одной и той же молнии. Когда создается молния, ваша позиция находится прямо над деревом:
(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