为什么在Clojure中使用recur会导致崩溃?

时间:2016-11-23 20:09:35

标签: recursion clojure tree

我有这个数据结构:

(def initial-map {:name "Root"
                  :children [{:name "Child1" :children [{:name "Grandchild1"}]}
                             {:name "Child2"}
                             {:name "Child3"}]})

我需要把它变成这样的东西:

[["Root" 0] ["Child1" 1] ["Child2" 1] ["Child3" 1] ["Grandchild1" 2]]

其中数字表示数据结构中节点的深度。

我写过这个函数试图从第一个到第二个:

(defn node-xform [ret nodes depth]
  (if empty? nodes)
  ret
  (recur (conj ret (map #(vector (:name %) depth) nodes))
         (flatten (map #(:children %) nodes))
         (inc depth)))

我这样称呼它

(node-xform [] (vector initial-map) 0)

但是当我这样做时,它会超时或者崩溃我的电脑......我做错了什么?

1 个答案:

答案 0 :(得分:2)

if表单应如下所示:

(if conditional-expr true-expr false-expr)

false-expr实际上是可选的,默认值为nil,如果它没有关闭 - 但我不认为这是你想要的。看来您希望在ret为空时返回nodes,否则返回recur

(defn node-xform [ret nodes depth]
  (if (empty? nodes) ; <-- fixed this line
    ret
    (recur (conj ret (map #(vector (:name %) depth) nodes))
           (flatten (map #(:children %) nodes))
           (inc depth)))) ; <-- added another close-paren here for the "if"

我实际上并未测试是否会返回您的预期答案,但这至少会消除您的无限递归问题。

您的代码会导致无限循环,因为node-xform 总是执行recur形式,这会导致无限的尾递归。更正if表单的语法使得recur表达式仅在nodes非空时执行。