堆栈溢出和递归序列表达式 F#

Ove*_*ive 5 recursion f# tail-recursion fibonacci lazy-sequences

我有一个像这样的序列表达式:

let fibSeq = 
    let rec fibSeq' a b = 
        seq { yield a
              yield! fibSeq' b (a + b) }
    fibSeq' 1 1
Run Code Online (Sandbox Code Playgroud)

现在,即使对于很大的数字,这也不会产生堆栈溢出。我想知道为什么,在我看来,要使用此序列表达式生成n 个斐波那契数,每个递归调用都需要返回到调用者,最终将其自身“折叠”到序列中。这里是否有某种优化在幕后进行?

Pet*_*etr 4

是的,它被称为“尾部调用优化”请参见此处: http: //blogs.msdn.com/b/chrsmith/archive/2008/08/07/understanding-tail-recursion.aspx 另外,Seq 是惰性的,因此它的第 500 个成员将除非您不必在程序中访问它,否则不会对其进行评估,例如:

let elm = Seq.nth 500 fibSeq
Run Code Online (Sandbox Code Playgroud)

  • @kaefer 是对的 - 序列表达式中的“尾递归”并不是真正的尾递归,因为“递归”调用实际上与对序列的“MoveNext”成员的调用交织在一起。事实上,甚至可以通过计算表达式中的非“尾递归”调用来避免堆栈溢出 - 请参阅http://stackoverflow.com/a/4251497/82959。 (4认同)
  • 我不明白 _tail call optimization_ 是如何进入其中的。使用反编译器查看,序列表达式被编译到对编译器生成的类的构造函数的初始调用中,该类实现了抽象类“Microsoft.FSharp.Core.CompilerServices.GenerateSequenceBase”,并且每次迭代随后都会构造它的一个新实例。那么尾部调用在哪里呢? (3认同)