首页 > 解决方案 > 为什么这不会在 mapcat 中再次发生终止?

问题描述

为什么 this inside 不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情况。

标签: recursionclojurecompiler-errorssequence

解决方案


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

是的简写

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

recur将递归到这个匿名函数,而不是任何外部函数,并且由于它不会改变任何东西,这是一个无限循环。

至于警告——众所周知,停止问题是无法解决的,即使只是尝试实施一些启发式方法,在编译时也有陷入死循环的风险。


推荐阅读