【问题标题】:Stack overflow during evaluation (looping recursion?). OCaml评估期间的堆栈溢出(循环递归?)。 OCaml
【发布时间】:2013-01-06 00:17:25
【问题描述】:

我正在尝试编写一个接受 int n 并返回从 n 到 0 的列表的函数。

这就是我所拥有的

let rec downFrom n =
let m = n+1 in
if m = 0 then                                                                                  
  []                                                                                           
else                                                                                            
  (m-1) :: downFrom (m - 1);;

函数编译正常,但是当我用任何 int 测试它时,它给了我错误 评估期间堆栈溢出(循环递归?)。

我知道这是本地变量的阻碍,但我不知道另一种声明它的方式。谢谢!!!

【问题讨论】:

    标签: functional-programming ocaml


    【解决方案1】:

    首先,你的程序真正的问题是你有一个无限循环。为什么,因为你的归纳基本情况是 0,但你总是留在n!这是因为你递归 m - 1 这实际上是 n + 1 - 1

    我很惊讶它为什么会编译,因为它不包含递归函数所必需的 rec 关键字。为避免 OCaml 中的堆栈溢出,一般切换为tail recursive 样式,如下所示:

    let downFrom n =
      let rec h n acc = 
        if n = 0 then List.rev acc else h (n-1) (n::acc)
      in
      h n []
    

    有人建议进行以下修改:

    let downFrom n =
        let rec h m acc =
            if m > n then acc else h (m + 1) (m::acc)
        in
        h 0 [];
    

    这节省了对 List.rev 的调用,我同意。

    【讨论】:

    • 谢谢!虽然我没有学习尾递归,但我将最后一条语句更改为 (m-1) :: downFrom (m - 2) 并且它有效
    • 作为提示,我会(为了更好的风格)简单地消除 m 的定义,而是在所有地方用 n+1 替换它,否则看起来很尴尬。
    • 我已更正了一些拼写错误,以便编译您的 downFrom 版本。但是,它仍然返回一个递增的列表,而 OP 要求一个递减的列表。
    【解决方案2】:

    递归的关键是递归调用必须是问题的较小版本。您的递归调用不会创建较小版本的问题。它只是重复同样的问题。

    【讨论】:

      【解决方案3】:

      您可以尝试使用过滤参数 语法:

      let f = function
         p1 -> expr1
       | p2 -> expr2
       | p3 -> ...;;
      

      let rec n_to_one =function
        0->[]
        |n->n::n_to_one (n-1);;
      
      # n_to_one 3;;
      - : int list = [3; 2; 1]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-29
        • 1970-01-01
        • 2020-09-23
        • 2015-02-08
        • 1970-01-01
        • 2020-12-17
        • 2015-04-04
        • 2017-01-20
        相关资源
        最近更新 更多