为什么在mapcat中这种重复出现不会终止?

时间:2018-09-30 16:43:32

标签: recursion clojure compiler-errors sequence

为什么recur中的mapcat不会终止,而等效的命名为fn的呼叫版本却会终止?

(def tree [1 [2 [3 5]] [6 [[1 2] [8 [9 10]]]]])

(defn leaves
  [node]
  (mapcat #(if (vector? %) (leaves %) [%]) node))

(leaves tree)
;; => (1 2 3 5 6 1 2 8 9 10)

(defn leaves-with-recur
  [node]
  (mapcat #(if (vector? %) (recur %) [%]) node))

(leaves-with-recur tree)
;; Never terminates

如果recur的这种使用是直截了当的禁止,那么是否有任何原因导致Clojure编译器不应该捕获这种情况并警告程序员,甚至拒绝对其进行编译?例如,recur的非尾位置调用就是这种情况。

1 个答案:

答案 0 :(得分:1)

#(if (vector? %) (recur %) [%])

的简写
(fn [%]
  (if (vector? %)
    (recur %)
    [%]))

recur将递归到该匿名函数,而不是任何外部函数,并且由于它不会改变任何内容,因此这是一个无休止的循环。

关于警告-停顿问题是无法解决的,并且即使在尝试实施一些启发式方法时,也有可能在编译时陷入无限循环的风险。