我有以下 Clojure 代码来计算具有特定“可分解”属性的数字。(代码的确切作用是次要的)。
(defn factor-9
([]
(let [digits (take 9 (iterate #(inc %) 1))
nums (map (fn [x] ,(Integer. (apply str x))) (permutations digits))]
(some (fn [x] (and (factor-9 x) x)) nums)))
([n]
(or
(= 1 (count (str n)))
(and (divisible-by-length n) (factor-9 (quot n 10))))))
现在,我进入 TCO 并意识到 Clojure 只有在使用recur
关键字明确告知时才能提供尾递归。所以我重写了代码来做到这一点(用 recur 替换 factor-9 是唯一的区别):
(defn factor-9
([]
(let [digits (take 9 (iterate #(inc %) 1))
nums (map (fn [x] ,(Integer. (apply str x))) (permutations digits))]
(some (fn [x] (and (factor-9 x) x)) nums)))
([n]
(or
(= 1 (count (str n)))
(and (divisible-by-length n) (recur (quot n 10))))))
据我所知,TCO 有双重好处。第一个是它没有像非尾递归调用那样大量使用堆栈,因此不会在更大的递归上破坏它。第二个,我认为因此它更快,因为它可以转换为循环。
现在,我做了一个非常粗略的基准测试,但没有看到这两种实现之间有任何区别。我的第二个假设是错误的,还是这与在 JVM(没有自动 TCO)上运行并recur
使用技巧来实现它有关?
谢谢你。