非尾递归触底之后会发生什么

时间:2018-07-26 21:53:12

标签: recursion

我是递归的新手,并且一直在研究非尾递归。我相信这是递归调用不在函数末尾的地方。我在看一些递归代码示例,对于执行递归调用后的代码时间和方式感到困惑。更具体地说,当程序的当前行到达递归调用时,是在再次实际执行整个功能之前执行的最后一段代码,还是当前执行的行立即跳回到函数的开头,仅在整个递归触底之后执行剩余的代码位?有人可以说明这对我如何工作吗?

1 个答案:

答案 0 :(得分:0)

在这里想象一下这段代码:(我在这里使用JS,但是它适用于所有热切的语言)

function add(a, b) {
  return a + b;
}

function sub(a, b) {
  return a - b;
}

function fib(n) {
  if (n < 2) {
    return n;
  } else {
    return add(
      fib(sub(n, 2)),
      fib(sub(n, 1)),
    );
  }
}

console.log(fib(10));

现在,当n2时,我们将对两个前任调用fib的结果添加到n中。某些调用之间的顺序是由JS引擎选择的,但是需要调用sub并返回,然后fib可以获取值并在两个参数都具有结果时调用add。可以使用延续传递样式将其重写为尾部调用:

function cadd(a, b, k) {
  k(a + b);
}

function csub(a, b, k) {
  k(a - b);
}

function cfib(n, k) {
  if (n < 2) {
    k(n);
  } else {
    csub(n, 2, n2 =>
      cfib(n2, rn2 =>
        csub(n, 1, n1 =>
          cfib(n1, rn1 =>
            cadd(rn2, rn1, k)))));
  }
}

cfib(10, console.log);

在这里您看到引擎选择的顺序从左到右都是明确的。每个调用都做一件事,然后继续调用该结果。还要注意,这永远不会返回任何东西。 “返回”仅通过继续来完成,但其功能与之前的代码完全相同。

在许多语言中,它们都可以编译成相同的语言。