尾递归优化:为什么“+”不允许?

Gra*_*ett 0 javascript recursion tail-recursion

所以我看到的尾递归的常见例子之一是:

function factorial(x) {
    if (x <= 0) {
        return 1;
    } else {
        return x * factorial(x-1); // (A)
    }
}
Run Code Online (Sandbox Code Playgroud)

它针对尾调用进行了优化:

function factorial(n) {
    return facRec(n, 1);
}
function facRec(x, acc) {
    if (x <= 1) {
        return acc;
    } else {
        return facRec(x-1, x*acc); // (A)
    }
}
Run Code Online (Sandbox Code Playgroud)

我明白了。但我的问题是:为什么*在这种情况下不是可以优化的功能?我不能将顶部重写为

function factorial(x) {
    if (x <= 0) {
        return 1;
    } else {
        return multiply(x, factorial(x-1)); // (A)
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道这行不通。我认为这只是因为它不是真正的尾递归调用?不过,这仍然是尾部优化吗?

T.J*_*der 7

您的最后一个示例不是尾调用,因为您必须factorial 调用multiply. 考虑:

阶乘(5)
  在得到 factorial(4) 的结果之前不能调用乘法
    在得到 factorial(3) 的结果之前不能调用乘法
      在得到 factorial(2) 的结果之前不能调用乘法
        在得到 factorial(1) 的结果之前不能调用乘法
          在得到 factorial(0) 的结果之前不能调用乘法

只有在这一点上,您才停止递归并调用multiply. 所以,没有尾声。

可能还值得注意的是,TCO 几乎仅由 Safari 的 JavaScriptCore 实现。它不是由 Chrome 的 V8 或 Firefox 的 SpiderMonkey 实现的,也不太可能是规范或没有规范。:-) 更多这里这里

我应该注意到,在你的标题中你问

为什么“+”不允许?

确实如此。TCO 并不关心操作是什么 -*+ - 只是它处于尾部位置。