Recursion 为什么OCaml中的递归比C++;还是Java?

Recursion 为什么OCaml中的递归比C++;还是Java?,recursion,ocaml,Recursion,Ocaml,caml.inria.fr网站上的这篇文章说 与C++和java相反,O-CAML[SiC]中的递归与迭代< /P>一样有效。 对于阶乘之类的东西,使用可变变量的循环似乎比递归调用涉及的堆栈操作更有效 C++语言的函数编程结构是否能使编译器更容易识别和优化递归? 见: 如果您以递归方式而不是迭代方式编写代码,那么在大型输入上必然会耗尽堆栈空间,对吗? 事实上,这是错误的。编译器可以对某些类型的递归函数执行简单的优化,将它们转换为while循环 我建议: OCaml的编译器将尾部递归优化为迭代结

caml.inria.fr网站上的这篇文章说

与C++和java相反,O-CAML[SiC]中的递归与迭代< /P>一样有效。 对于阶乘之类的东西,使用可变变量的循环似乎比递归调用涉及的堆栈操作更有效


C++语言的函数编程结构是否能使编译器更容易识别和优化递归? 见:

如果您以递归方式而不是迭代方式编写代码,那么在大型输入上必然会耗尽堆栈空间,对吗?

事实上,这是错误的。编译器可以对某些类型的递归函数执行简单的优化,将它们转换为while循环

我建议:

  • OCaml的编译器将尾部递归优化为迭代结构;还有可能
  • 所有其他递归类型都通过迭代和堆栈对象进行了优化,以模拟递归调用(我没有找到任何文档支持这一点)
  • 我知道,至少.Net/C不太可能跨功能边界进行优化。例如,内嵌函数必须使用属性显式请求,甚至可能仍然不能。JIT可能是内联的,可能会优化递归,但似乎不会。这可能适用于Java


    我不确定C++,它将取决于你使用的编译器。

    < P>语言的函数编程结构可能使编译器更容易识别和优化递归。 见:

    如果您以递归方式而不是迭代方式编写代码,那么在大型输入上必然会耗尽堆栈空间,对吗?

    事实上,这是错误的。编译器可以对某些类型的递归函数执行简单的优化,将它们转换为while循环

    我建议:

  • OCaml的编译器将尾部递归优化为迭代结构;还有可能
  • 所有其他递归类型都通过迭代和堆栈对象进行了优化,以模拟递归调用(我没有找到任何文档支持这一点)
  • 我知道,至少.Net/C不太可能跨功能边界进行优化。例如,内嵌函数必须使用属性显式请求,甚至可能仍然不能。JIT可能是内联的,可能会优化递归,但似乎不会。这可能适用于Java


    我不确定C++,它将取决于你使用的编译器。

    < P>是的,在某些情况下。这叫做尾部调用优化。以以下C-ish阶乘函数为例:

    int factorial(int n) 
    {
            if (n < = 1)
                    return 1;
            else
                    return n * factorial(n – 1);
    }
    
    当然,可以多次调用此函数,而不会使堆栈溢出(即使会很快使32位int溢出)。实际上,可以用OCaml编写同义函数。现在,OCaml的版本将再次使用递归。但是,如果我们在第一个函数中添加一个“累加器”参数,它可以重新编写为:

    let factorial acc n = if n <= 1 then acc else factorial (acc * n) (n – 1)
    

    让阶乘acc n=如果n是,在某些情况下。这叫做尾部调用优化。以以下C-ish阶乘函数为例:

    int factorial(int n) 
    {
            if (n < = 1)
                    return 1;
            else
                    return n * factorial(n – 1);
    }
    
    当然,可以多次调用此函数,而不会使堆栈溢出(即使会很快使32位int溢出)。实际上,可以用OCaml编写同义函数。现在,OCaml的版本将再次使用递归。但是,如果我们在第一个函数中添加一个“累加器”参数,它可以重新编写为:

    let factorial acc n = if n <= 1 then acc else factorial (acc * n) (n – 1)
    

    let factorial acc n=如果在OCaml和其他函数语言中,一些“好的”递归调用被编译成仅仅是跳转,那么它与循环一样有效。更严格地说,“好”是指尾部位置,但在我看来,文档有意跳过这一点,因为它只是介绍性的目的。适当使用“[sic]”,但“OCaml”也不是您编写它的方式。(“OCaml”在2001年左右我写博士论文的时候就已经是应该写的了,但那时还不是正式的。)一些“好的”递归调用在OCaml和其他函数语言中被编译成仅仅是跳转,因此它和循环一样有效。更严格地说,“好”是指尾部位置,但在我看来,文档有意跳过这一点,因为它只是介绍性的目的。适当使用“[sic]”,但“OCaml”也不是您编写它的方式。(“OCaml”在2001年左右我写博士学位的时候就已经是应该写的了,但那时它不是官方的)。
    
    let factorial n =
        let loop acc n' = if n' <= 1 then acc else loop (acc * n') (n' – 1) in
        loop 1 n