代码之家  ›  专栏  ›  技术社区  ›  SLaks

确定性尾部调用递归问题

  •  3
  • SLaks  · 技术社区  · 14 年前

    在参加了年的辩论之后 this fiasco question ,我想向整个社会提出这个问题。

    在什么情况下,尾部调用优化将应用于基于.Net的代码?

    请用可靠、最新的来源或可重复的实验来支持您的答案。

    1 回复  |  直到 7 年前
        1
  •  4
  •   Boann    8 年前

    根据Don Syme等人写的“专家F#”的说法,F#进行尾部调用优化。我似乎记得在Eric Lippert的博客上读到C#编译器(任何版本)都没有。如果我错了,请纠正我,埃里克。在所有情况下,当最后一条指令是调用一个方法时,都可以进行尾部调用优化。这通常是方法本身的递归调用,但不需要这样做。可以进行优化,因为可以保证不再需要当前堆栈帧。但是,如果之后必须执行简单的操作,则无法执行优化。

    int Fib(int n)
    {
      if(n < 2)
         return 1;
    
      return Fib(n-1) + Fib(n-2);
    }
    

    这无法进行尾部调用优化,因为 + 无法在最后一次调用之前计算 Fib 返回(事实上,我认为这也是专家F#中使用的示例,但不确定是否适用于该示例。)

    int Fib(int n, int a, int b)
    {
      if(n == 0)
        return a+b;
      return Fib(n-1,a+b,a);
    }
    

    此版本可以进行尾部调用优化,因为所有参数都经过计算 之前 最后一次调用Fib,调用后不存在要执行的操作,因此可以丢弃当前堆栈帧。