Clojure 是我第一次涉足 lisp 世界。我决定尝试一个简单的递归函数,将数字提高到整数次幂。足够简单。
(defmulti pow #(compare %2 0))
(defmethod pow 0 [a n] 1)
(defmethod pow 1 [a n] (* a (pow a (dec n))))
(defmethod pow -1 [a n] (/ 1 (pow a (* -1 n))))
如果你只传递整数幂,它就可以正常工作。但是当我使用它来提高足够大的功率时,我会发生堆栈溢出(可以预见)。
问题是,我如何才能准确地知道函数在死亡之前递归的深度?大致了解递归深度的一种方法是执行以下操作:
(defn max-depth [n]
(try
(max-depth (inc n))
(catch StackOverflowError err (do
(printf "%s at %d\n" err n)
n)
)))
(Clojure 是我第一次接触 lisp,所以我真的不知道如何让代码看起来可读。)这段代码只是无限递归,直到溢出堆栈,然后返回之前发生的递归次数爆炸了。这只能给我一个大概的数字,让我知道我可以走多深……这种方法存在很多问题。
我能做的另一件事是捕获异常并尝试自己展开堆栈...但我真的没有找到一种方法来从异常中获取我想要的信息。查看 StackOverflowError 的 javadoc http://docs.oracle.com/javase/6/docs/api/java/lang/StackOverflowError.html我看到了一些看起来很有希望的方法,但据我所知,没有任何结果。
我尝试运行 (count (.getStackTrace error)) ,其中错误是我捕获的堆栈溢出,但结果仅为 1024,因为“在某些情况下,堆栈帧可能会被忽略”。所以这不起作用。
我能想到的唯一的另一件事是对连续较大的指数运行 pow,但这并不能真正告诉我调用堆栈有多深,它只告诉我可以提高到多大的指数(由于该函数调用了其他函数,因此两个答案并不相同)。
我也不知道用java有什么方法可以做到这一点,但如果有的话,那么这个答案也可能会有所帮助。
有什么想法吗? 谢谢, ——斯科特
最佳答案
我认为 (.getStackTrace error)
是你最好的选择 - 为什么你认为它不起作用?
在一个简单函数的堆栈销毁之前,递归深度为 1024 听起来符合我的预期。
请记住,单个 Clojure 函数通常会转换为多个 JVM 方法调用,因此实际的 JVM 堆栈深度可能比递归有效值 n
深得多。如果您想从堆栈跟踪转换回 n
,您可能需要计算对多方法的递归调用出现在堆栈跟踪中的次数。
关于recursion - 了解 Clojure(或 java)中调用堆栈的深度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16880385/