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

火星

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

相关问题:Clojure可以将看似递归的代码转换成一个循环:如果程序员用关键字替换函数的尾调用,它就好像在执行TCO recur但是,如果有可能让编译器识别出尾调用(例如SBCL和CCL那样),那么为什么Clojure编译器不能弄清楚它应该以对待尾调用的方式来对待recur

(很抱歉,这无疑是一个常见问题解答,我敢肯定,上面的评论显示出我的无知,但我未能找到较早的问题。)

米歇尔·马尔奇克(MichałMarczyk)

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

(letfn [(e? [x] (or (zero? x) (o? (dec x))))
        (o? [x] (e? (dec x)))]
  (e? 10))

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

至于消除尾部位置的自调用,这是一个更简单的问题,只要将整个函数体编译为单个JVM方法即可解决。但是,那是一个有限的承诺。此外,recur它的明确性也颇受好评。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么JVM仍然不支持尾调用优化?

为什么我不能在addEventListener中调用类函数

为什么我不能在回调中调用useRef?

为什么我不能在 React 中调用这个函数?

为什么不能在函数中调用全局变量?

为什么不能在jquery中递归调用函数?

为什么不能在$(this)上调用externalHTML?

在Java中尾调用优化

为什么Bash`(())`不能在`[[]]`中工作?

在main中调用时,为什么我的程序不能在方法中接受int []参数?

为什么我不能在Xcode 9.2中的数组常量上调用reduce(into :)?

为什么我不能在我的回调中调用我的 vue 组件的函数

为什么我不能在 python 中读取这个子进程调用的输出?

为什么不能在Java中调用添加到匿名类的方法?

为什么我不能在代码中调用任何方法?

为什么我不能在我的播放器功能中调用我的敌人边界?

为什么不能在Java中的空指针上调用方法?

为什么我不能在另一个类中调用静态方法?

为什么我不能在扩展通用特征的类中调用带有参数“ this”的方法?

为什么我不能在Swift中的UIViewController上调用默认的super.init()?

为什么我不能在settimeout / setinterval中多次调用带有参数的函数

为什么带有参数的函数不能在迭代器中调用?

为什么我不能在ColdFusion 8中调用java-apns getInactiveDevices()方法?

为什么我不能在 php 的 try 块中定义函数之前调用它

为什么我不能在WPF中通过System.Threading.Timer调用使用CapturePhotoToStreamAsync?

为什么我不能在VueJS / Vuex中调用命名空间的getter?

为什么不能在使用速记的函数调用中减少数字?即++或-

为什么我不能在 .spec.ts 中调用组件的函数?

为什么不能在Groovy中内联调用正则表达式匹配器的方法