我只是一个Clojure的初学者,一直在尝试4clojure.com的问题。在那里,我遇到了一个练习中的问题,我应该写一个
我基本上理解尾调用优化的概念,以及如何使用
这就是为什么我不明白这里发生了什么:
flatten
实现。我基本上理解尾调用优化的概念,以及如何使用
recur
来避免消耗堆栈,而不是“普通”的递归(我不知道是否有一个正确的术语)。这就是为什么我不明白这里发生了什么:
(defn foo1 [x]
(if (> x 0)
(do (println x)
(foo1 (dec x)))))
(defn foo2 [x]
(if (> x 0)
(do (println x)
(recur (dec x)))))
如预期,foo1
和foo2
在功能上是相同的,但是,给定一个足够大的参数(在我的情况下是100000),foo1
会导致堆栈溢出,而foo2
能够正常完成。
现在,让我们来看一下flatten
问题:
(defn flatten1 [ls]
(mapcat
#(if (coll? %)
(flatten1 %)
(list %))
ls))
(defn flatten2 [ls]
(mapcat
#(if (coll? %)
(recur %)
(list %))
ls))
测试案例:
(flatten [1 [2] 3 [4 [5 6 [7] 8]]])
(flatten1 [1 [2] 3 [4 [5 6 [7] 8]]])
(flatten2 [1 [2] 3 [4 [5 6 [7] 8]]])
预期结果:'(1 2 3 4 5 6 7 8)
好的,flatten1
运行良好(这是一个很小的输入)。但是 flatten2
无限期地挂起。 recur
不是针对在 defn
处设置的递归点进行操作吗?与通过名称递归函数有什么区别(除了优化之外)?