【问题标题】:Will OCaml compiler deal with boolean operators to make recursion tail-recursive?OCaml 编译器会处理布尔运算符以使递归尾递归吗?
【发布时间】:2014-12-17 01:03:45
【问题描述】:

我们看看下面的函数is_prime

let is_prime n =
  let rec div_check i = i * i > n || (n mod i <> 0 && div_check (i+1))
  in
  n >= 2 && div_check 2

所以如果n mod i &lt;&gt; 0false,那么它就会停止。

但是如果n mod i &lt;&gt; 0true,那么它会递归地继续。

我的问题是,如果它继续下去,OCaml 是否优化了编译器,所以只直接返回 div_check(i+1),即尾递归?还是会保留true &amp;&amp; 部分并等待div_check 返回?

ps函数取自http://www.cs.cornell.edu/Courses/cs3110/2014sp/lectures/2/lec02.html

【问题讨论】:

    标签: ocaml


    【解决方案1】:

    答案是肯定的。我已经简化了您的示例,以使编译器输出更易于理解:

    let rec is_prime n =
      let rec div_check i =
        i * i > n || (i + i < n && div_check (i+1)) in
      div_check n
    

    鉴于此输入,编译器将发出以下程序集(我添加了一些注释):

    camlIs_prime__div_check_1010:
    .L102:
        movq    16(%rbx), %rdi
        movq    %rax, %rsi
        sarq    $1, %rsi
        movq    %rax, %rdx
        decq    %rdx
        imulq   %rsi, %rdx           ; i * i
        incq    %rdx
        cmpq    %rdi, %rdx           ; if i * i <= n then return
        jle .L101
        movq    $3, %rax
        ret
    .L101:
        movq    16(%rbx), %rdi
        leaq    -1(%rax, %rax), %rsi ; i + i
        cmpq    %rdi, %rsi           ; i + i ? n
        jge .L100                    ; if i + i >= n then return
        addq    $2, %rax             ; else i := i + 1
        jmp .L102                    ;      div_check i
    .L100:
        movq    $1, %rax
        ret
    

    但要小心,这仅适用于普通 OCaml 的短路运算符。 即使是let (&amp;&amp;) = (&amp;&amp;)breakjmp .L102 这样的无害更改也将替换为call camlIs_prime__div_check_...

    此外,这仅在调用位于短路运算符右侧时才有效。左表达式为 marked 非尾递归。我已经对其进行了测试,确实,将div_check 放在&amp;&amp; 运算符的左侧将发出非尾递归代码。

    如果您不确定调用是否为尾,您可以随时在编译器中添加-annot 标志,并查看对应的*.annot 文件,以获取call (tail) 注释。 merlin 中有一些工具支持,但我还没有弄清楚如何正确使用它。请记住,最终的判断仍然是汇编输出。

    【讨论】:

    • 可以 i + i > n 替换 n mod i 0 吗?
    • 只是为了说明短路调用是尾递归的,函数的语义当然改变了。如果我加回n mod i &lt;&gt; 0,编译器将发出几个按键,这些按键也会检查除以零,否则,调用仍然是尾递归的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    相关资源
    最近更新 更多