Recursion 想通过一个例子生动地说明尾部递归调用比非尾部递归调用占用更少的空间吗?

Recursion 想通过一个例子生动地说明尾部递归调用比非尾部递归调用占用更少的空间吗?,recursion,functional-programming,f#,tail-recursion,biginsight-examples,Recursion,Functional Programming,F#,Tail Recursion,Biginsight Examples,函数式编程语言的软件开发人员被告知尾部递归调用比非尾部递归调用更好。教科书中的一个经典例子是尾部递归阶乘函数(用F#编写) 相对于它的非尾部递归计数器部分 let rec facr n = if n = 0 then 1 else n * facr(n-1) 相对清楚的是,上面的faci在调用自身时不需要额外的堆栈帧,正如facr所做的那样。但我正在寻找一个更生动的例子,最好是F#,从中可以说明为什么尾部递归函数比非尾部递归函数更好。理想情况下,改进可以可视化,例如,使用内存分析器,或者

函数式编程语言的软件开发人员被告知尾部递归调用比非尾部递归调用更好。教科书中的一个经典例子是尾部递归阶乘函数(用F#编写)

相对于它的非尾部递归计数器部分

let rec facr n = 
  if n = 0 then 1 else n * facr(n-1)

相对清楚的是,上面的
faci
在调用自身时不需要额外的堆栈帧,正如
facr
所做的那样。但我正在寻找一个更生动的例子,最好是F#,从中可以说明为什么尾部递归函数比非尾部递归函数更好。理想情况下,改进可以可视化,例如,使用内存分析器,或者通过打印一些调试信息。对这样的例子有什么想法吗?

尾部递归依赖于累加器。如果累加器只是一个单独的计算值(如示例中所示),则尾部递归需要更少的内存。但是,如果它累积每个递归步骤的结果而不丢失信息(例如,在列表中),则本质上可以用调用堆栈交换堆。不过,它可能仍然更节省内存。很高兴知道这一点。谢谢tbh,这可能不像你想的那么简单。例如,编译器会将一些tailcall优化到一个循环中。递归函数只有在尾部递归的情况下才更好,否则它们会把你的堆栈吃掉。我同意上面的说法,我将通过使用循环(在C#中)演示阶乘,然后递归地演示阶乘来演示它。
let rec facr n = 
  if n = 0 then 1 else n * facr(n-1)