我找不到文章描述为什么尾递归函数应该优先于迭代算法。
我不是在问尾递归为什么比简单递归更好,因为我认为这已经得到了清晰的解释。
那么为什么呢?
sum(n) = {
def sumImpl(n, acc) = if(n <= 0) acc else sumImpl(n - 1 , n + accumulator)
sumImpl(n, 0)
}
更可取
sum = 0;
while(n--) sum += n
我找不到文章描述为什么尾递归函数应该优先于迭代算法。
我不是在问尾递归为什么比简单递归更好,因为我认为这已经得到了清晰的解释。
那么为什么呢?
sum(n) = {
def sumImpl(n, acc) = if(n <= 0) acc else sumImpl(n - 1 , n + accumulator)
sumImpl(n, 0)
}
更可取
sum = 0;
while(n--) sum += n
我认为答案在于你选择的编程范式。
声明式风格(如函数式编程中的Scala)与命令式风格(如Java中的迭代)。
在函数式范式中,我们希望避免副作用。因此,我们希望处理表达式,即返回值的代码。使用递归函数是一种方法。
在Java中,我们可能会在循环内更改对象的状态,这将被视为副作用。
总之,两种方法都不一定是坏的。然而,在函数式语言中,我们应该避免使用命令式结构,如循环,而应使用递归。
递归消耗更多的内存(堆栈帧的开销)和更多的CPU周期(创建和销毁堆栈帧的开销)。但它使代码更易读。迭代使代码不太易读,但释放更多的内存和CPU,因此在受限环境下可能需要,例如物联网设备、手机等。请参阅此处的良好描述https://www.ocf.berkeley.edu/~shidi/cs61a/wiki/Iteration_vs._recursion#:~:text=Iteration%20and%20recursion%20are%20both%20ways%20to%20achieve%20repetition%20in%20programs.&text=All%20iterative%20functions%20can%20be,is%20defined%20as%20tail%20recursion。
sum1(n-1)
,其中我用sum1
代替了你也称为sum
的第一个函数。手动迭代往往比其语法递归形式更容易出现此类错误。具体来说,while(n--)
在将n
加入累加器之前会使n
减一,因此第一个n
值被忽略了。 - Will Ness