首页 > 解决方案 > 如何在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?返回 aTrue时,clojure 怎么会走进:yes节点或:send-out-email节点?我以为只有z/down一段时间,left或者right只是为了兄弟姐妹而不是为了孩子的方向。

非常感谢您的宝贵时间并感谢您的任何想法

标签: clojurezipper

解决方案


拉链在跟踪当前位置的同时遍历数据结构。要到达不同的节点,您必须对同一个拉链应用一系列移动。创建拉链后,您的位置就在树的正上方:

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

因此,您可以使用 , 下降到树中z/down,并用于z/node从拉链的位置获取当前节点:

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

如果您从树的顶部走向某个节点,您可能只需要z/downand 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

推荐阅读