【问题标题】:Why tail recursive function fails for a input for which normal recursive function execute successfully?为什么正常递归函数成功执行的输入的尾递归函数失败?
【发布时间】:2012-04-11 12:20:14
【问题描述】:

根据MSDN 文档,在编写递归函数时,累加器参数的使用使函数尾递归,从而节省了堆栈空间。 我正在使用 MSDN 网站上给出的两个示例来计算列表中所有数字的总和-

第一个没有尾递归-

let rec Sum myList =
    match myList with
    | [] -> 0
    | h::t -> h + Sum t

现在有了尾递归-

let Sumtail list =
    let rec loop list acc =
        match list with
        | h::t -> loop t acc + h
        | [] -> acc
    loop list 0

并使用输入 [1..100000] 运行这两个函数。 函数Sum 成功计算了这个列表的总和,但如果我通过[1..1000000] 则会给出stackoverflow 异常 但是第二个函数Sumtail[1..100000] 失败,而它应该比第一个函数提供更好的性能,因为它使用尾递归。 还有其他影响递归函数的因素吗?

【问题讨论】:

  • 我相信你误解了一些东西——使用累加器参数不会使函数尾递归。累加器参数是一种在使用尾递归函数时累加值的技术。这是一种通常与尾递归相关的技术,但它没有定义尾递归。

标签: f# tail-recursion


【解决方案1】:

您的第二个函数不是尾递归的,因为loop t acc + h 被解析为(loop t acc) + h,这使得+ 成为loop 上的最后一个操作。

loop t acc + h 更改为 loop t (acc + h) 以使函数变为尾递归。

【讨论】:

  • 没错,但我无法正确标记(还有 6 分钟)。这有什么区别?
  • 必须将“+”运算符应用于循环的返回值,因此编译器不能使用尾递归,这会忘记每个递归调用的 h 状态。如果可以忘记状态,尾递归就可以工作 - 如果我们知道返回值将通过所有未修改的堆栈帧返回。
猜你喜欢
  • 2019-09-14
  • 1970-01-01
  • 2016-01-06
  • 2020-09-16
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多