人们说除了没有尾调用优化的限制之外,clojure 实现非常出色 - jvm 的限制而不是 clojure 实现。
http://lambda-the-ultimate.org/node/2547
据说在 Python 中实现 TCO 会牺牲
- 堆栈跟踪转储,以及
- 调试规律。
向我解释尾调用优化有什么大不了的,为什么 Python 需要它
是否必须为 TCO 的 jvm 实现做出同样的牺牲?还要牺牲什么吗?
人们说除了没有尾调用优化的限制之外,clojure 实现非常出色 - jvm 的限制而不是 clojure 实现。
http://lambda-the-ultimate.org/node/2547
据说在 Python 中实现 TCO 会牺牲
向我解释尾调用优化有什么大不了的,为什么 Python 需要它
是否必须为 TCO 的 jvm 实现做出同样的牺牲?还要牺牲什么吗?
虽然不同(因为 il 指令已经存在)但值得注意的是 .Net 64 位 JIT 团队必须通过额外的努力来尊重所有尾调用。
我特别呼吁评论:
当然,不利的一面是,如果您必须调试或分析优化的代码,请准备好处理看起来缺少几帧的调用堆栈。
我认为 JVM 也极不可能避免这种情况。
鉴于此,在请求尾调用优化的情况下,JIT 应该假设需要避免堆栈溢出,这不是可以在 Debug 构建中关闭的东西。如果它们在您到达有趣的部分之前崩溃,它们对调试没有多大用处。“优化”实际上是一个永久性功能,并且是受其影响的堆栈跟踪的问题。
值得指出的是,在执行程序员在概念上描述/理解为堆栈操作(例如调用函数)的操作时避免创建真实堆栈帧的任何优化都会固有地导致呈现给用户的内容之间的断开连接在调试/提供堆栈跟踪和现实时。
这是不可避免的,因为描述操作的代码与执行操作的状态机的机制越来越分离。
是的,通常情况下,实施 TCO 会阻止您获得完整的堆栈跟踪。这是不可避免的,因为 TCO 的重点是避免创建额外的堆栈帧。
值得一提的是,Clojure 有一个不消耗堆栈的“recur”特性来绕过当前 JVM 版本的这个限制。
例子:
(defn triangle [n accumulator]
(if
(<= n 0)
accumulator
(recur (dec n) (+ n accumulator))))
(triangle 1000000 0)
=> 500000500000 (note stack does not explode here!)