![]() |
1
47
是的,实际上你 可以 使用一些代码,将每个函数调用和每个返回都转换为尾部调用。您最终得到的是称为连续传递样式(ContinuationPassingStyle)或CPS。 例如,下面是一个包含两个递归调用的函数:
下面是将此函数转换为连续传递样式时的外观:
额外的论点,
我没有把电话转换成
现在是有趣的部分。 Chicken Scheme 实际上,在它编译的所有代码上进行这种转换。鸡编程序 永不回头 .有一篇经典的文章解释了为什么鸡计划会这样做,这篇文章写于1994年,在鸡被实施之前: CONS should not cons its arguments, Part II: Cheney on the M.T.A.
令人惊讶的是,延续传递样式在JavaScript中相当常见。你可以用它
to do long-running computation
避免浏览器的“慢脚本”弹出。它对异步API很有吸引力。
|
![]() |
2
26
观察到任何相互递归函数的集合都可以转换为尾部递归函数,这是正确的,但并不有用。这种观察与20世纪60年代的陈词滥调不谋而合,即控制流构造可以被消除,因为每个程序都可以被编写成一个循环,其中嵌套一个case语句。 需要知道的是,许多明显不是尾递归的函数可以通过添加 累积参数 . (这种转换的一个极端版本是转换为连续传递样式(CPS),但是大多数程序员发现CPS转换的输出很难读取。) 下面是一个“递归”(实际上只是迭代)而不是尾部递归的函数示例:
在这种情况下,乘法发生了 之后 递归调用。 我们可以通过将产品放入累积参数来创建尾端递归的版本:
内部功能
我发现以下区别很有用:
只有第一种程序有 简单的 转换为尾部递归形式。 |
![]() |
3
11
任何递归算法都可以重写为迭代算法(可能需要一个堆栈或列表),并且迭代算法总是可以重写为尾部递归算法,所以我认为任何递归解决方案都可以以某种方式转换为尾部递归解决方案是正确的。 (在评论中,PascalCuoq指出任何算法都可以转换为 continuation-passing style 。) 注意,仅仅因为尾部递归并不意味着它的内存使用是常量。这只意味着调用返回堆栈不会增长。 |
![]() |
Luiz Miranda · 尾递归pow-Erlang 7 年前 |
![]() |
Srinivas · Scala中的尾部递归 7 年前 |
![]() |
madtyn · Python:有可能使这个尾部递归阶乘更快吗? 7 年前 |
![]() |
clay · Scala中的尾部递归findNextAndTail 7 年前 |
![]() |
Sanitiy · 如何在调用另一个函数后强制函数退出? 7 年前 |
![]() |
Lorinc Nyitrai · Lua-将协程递归重写为尾部调用递归 7 年前 |
![]() |
Alex · 尾部递归调用(C primer加上书本示例) 9 年前 |
![]() |
Thomas Ahle · 递归联合查找是否可以优化? 9 年前 |
![]() |
beta Rob · 这个函数真的是尾部递归的吗? 11 年前 |