首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么不能在基于JVM的Lisp中优化尾部调用?

为什么不能在基于JVM的Lisp中优化尾部调用?
EN

Stack Overflow用户
提问于 2013-10-19 12:17:01
回答 3查看 7.6K关注 0票数 22

主要问题:我认为尾部调用优化(TCO)最重要的应用是将递归调用转换为循环(在递归调用具有特定形式的情况下)。更准确地说,当翻译成机器语言时,这通常会翻译成某种类型的跳转。一些编译为本机代码(例如SBCL)的Common Lisp和Scheme编译器可以识别尾递归代码并执行此转换。基于JVM的Lisp,比如Clojure和ABCL,很难做到这一点。JVM作为一台机器,是什么阻止或使这一点变得困难的?我还是不明白。显然,JVM在循环方面没有问题。编译器必须弄清楚如何实现TCO,而不是它编译到的机器。

相关问题: Clojure可以将看似递归的代码转换为循环:如果程序员将对函数的尾部调用替换为关键字recur,它的行为就像是在执行总体拥有成本。但是,如果可以让编译器识别尾部调用--例如,SBCL和CCL就是这样做的--那么为什么Clojure编译器不能弄清楚,它应该像处理recur一样处理尾部调用

(对不起--这无疑是一个常见问题,我确信上面的评论表明我的无知,但我没有成功地找到前面的问题。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-10-19 12:29:24

Real TCO适用于尾部位置的任意调用,而不仅仅是自身调用,因此如下所示的代码不会导致堆栈溢出:

代码语言:javascript
复制
(letfn [(e? [x] (or (zero? x) (o? (dec x))))
        (o? [x] (e? (dec x)))]
  (e? 10))

显然,您需要JVM支持,因为在JVM上运行的程序不能操作调用堆栈。(除非您愿意建立自己的调用约定并将相关的开销强加给函数调用;Clojure的目标是使用常规的JVM方法调用。)

至于消除尾部的自调用,这是一个更简单的问题,只要将整个函数体编译成一个JVM方法就可以解决。然而,这是一个有限的承诺。此外,recur还因为它的显性而广受欢迎。

票数 9
EN

Stack Overflow用户

发布于 2013-10-23 00:00:09

JVM不支持总体拥有成本是有原因的:Why does the JVM still not support tail-call optimization?

然而,有一种方法可以通过滥用堆内存和A First-Order One-Pass CPS Transformation paper中解释的一些技巧来解决这个问题;它是由Chris Frisz和Daniel P.Friedman用Clojure实现的(参见clojure-tco)。

现在Rich Hickey可以选择在默认情况下进行这样的优化,Scala在某些情况下会这样做。相反,他选择依靠最终用户来指定可以使用trampolineloop-recur结构通过Clojure进行优化的情况。这里解释了这个决定:https://groups.google.com/d/msg/clojure/4bSdsbperNE/tXdcmbiv4g0J

票数 4
EN

Stack Overflow用户

发布于 2015-07-10 22:44:26

在ClojureConj 2014的最后一次演讲中,Brian Goetz指出,JVM虚拟机中有一个安全功能,可以防止堆栈框架崩溃(因为这将是一个攻击载体,人们希望让函数返回到其他地方)。

https://www.youtube.com/watch?v=2y5Pv4yN0b0&index=21&list=PLZdCLR02grLoc322bYirANEso3mmzvCiI

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19462314

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档