首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么在递归函数中使用助手函数?

为什么在递归函数中使用助手函数?
EN

Stack Overflow用户
提问于 2020-09-16 08:57:09
回答 2查看 1.1K关注 0票数 4

在Scala中的函数式编程一书中,在解释递归是如何在命令式迭代的函数式编程中经常使用的上下文中,作者使用名为"go“或"loop”的助手函数通过阶乘函数显示递归,并声明这是Functional编程的标准实践:

代码语言:javascript
运行
复制
...
def factorial(n: Int): Int = {
  @tailrec def go(n: Int, acc: Int): Int = {
    if (n <= 0 ) acc
    else go(n - 1, n*acc)
  }
  go(n, 1)
}

因此,如果不是更简洁地定义它,如果没有助手函数,...but也同样容易:

代码语言:javascript
运行
复制
...
def factorial(n: Int): Int = {
  if (n <= 0) 1
    else n * factorial(n - 1)
}

我的理解是,累积值和避免变异是通过利用堆栈帧和将返回值“传递”到前一个堆栈帧来实现的。在这里,作者似乎为了类似的目的使用显式累加器参数。

使用助手函数来积累像这样的值有什么好处,还是用这个例子来显式地将状态传递给助手函数来显示递归与命令式迭代的关系?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-16 09:10:45

尾递归是一个重要的优化,它使递归函数更快,并避免了递归太深时的“堆栈溢出”。

无尾递归

代码语言:javascript
运行
复制
def factorial(n: Int): Int = {
  if (n <= 0) 1
    else n * factorial(n - 1)
}

当我想计算factorial(10)时会发生什么?首先,我计算factorial(9);然后,将结果乘以10。这意味着,在计算factorial(9)时,我需要在某个地方保留一个注释:“记住,当您完成factorial(9)时,仍然需要乘以10!”

然后,为了计算factorial(9),我必须先计算factorial(8),然后再把结果乘以9。所以我写了一个小注释:当你得到factorial(8)的结果时,记得乘以9。

这还在继续,最后我到达了factorial(0),也就是1。到这个时候,我有十个小音符,上面写着“当你用factorial(0)做完时,记得乘以1”,“当你用factorial(1)做完时,记得乘以2”等等。

这些音符被称为“堆栈”,因为它们实际上是堆叠在一起的。如果堆栈太大,程序就会崩溃,产生“堆栈溢出”。

尾递归

代码语言:javascript
运行
复制
def factorial(n: Int): Int = {
  @tailrec def go(n: Int, acc: Int): Int = {
    if (n <= 0 ) acc
    else go(n - 1, n*acc)
  }
  go(n, 1)
}

这个程序中的函数go是不同的。为了计算go(10, 1),您需要计算go(9, 10);但是当您计算完go(9, 10)之后,您就不需要做任何其他事情了!您可以直接返回结果。因此,不需要保留“记住在递归调用后将结果乘以10”。编译器优化了这种行为:它没有将对go(9, 10)的调用堆叠在对go(10, 1)的调用之上,而是将对go(10, 1)的调用替换为对go(9, 10)的调用。然后将对go(9, 10)的调用替换为对go(8, 90)的调用。因此,在递归过程中,堆栈不会增加。这称为尾递归,因为递归调用是函数执行过程中发生的最后一件事(特别是,在计算参数时会发生10乘)。

票数 8
EN

Stack Overflow用户

发布于 2020-09-16 09:11:38

因为尾部递归优化(尾递归优化)。

如果没有堆栈溢出(这个问题在这个站点上是多么具有讽刺意味的)异常,那么它的效率就会低得多(主要是通过内存)。

需要注意的是,@tailrec注释不执行或应用尾部优化,而是强制编译器在无法优化的情况下失败。

而尾递归优化要求您的下一个迭代函数调用应该完全是返回表达式(其中不需要额外的操作或计算)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63916567

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档