Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
OCaml编译器会处理布尔运算符以使递归尾部递归吗?_Ocaml - Fatal编程技术网

OCaml编译器会处理布尔运算符以使递归尾部递归吗?

OCaml编译器会处理布尔运算符以使递归尾部递归吗?,ocaml,Ocaml,让我们看一看下面的函数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 设为素数= 让rec div|u check i=i*i>n||(n mod i 0&&div|u check(i+1)) 在里面 n>=2&&div\u检查2 因

让我们看一看下面的函数
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
设为素数=
让rec div|u check i=i*i>n||(n mod i 0&&div|u check(i+1))
在里面
n>=2&&div\u检查2
因此,如果
nmodi0
为false,则它将停止

但是如果
nmodi0
为真,那么它将递归地继续

我的问题是,如果它继续,OCaml是否优化了编译器,因此只直接返回
div\u check(i+1)
,即尾部递归?或者它是否仍会保留
true&&
部分并等待
div\u check
返回


ps该函数取自答案是肯定的。我简化了您的示例,以使编译器输出更易于理解:

let rec is_prime n =
  let rec div_check i =
    i * i > n || (i + i < n && div_check (i+1)) in
  div_check n
让rec为素数=
让记录div_检查i=
i*i>n | |(i+i
给定此输入,编译器将发出以下程序集(我添加了一些注释):

camlIs\u prime\u div\u check\u 1010:
.L102:
movq 16(%rbx),%rdi
movq%rax,%rsi
sarq$1,%rsi
movq%rax,%rdx
decq%rdx
imulq%rsi,%rdx;我,我
增量%rdx
cmpq%rdi,%rdx;如果i*i=n,则返回
addq$2,%rax;否则i:=i+1
jmp.L102;第一分区支票
.L100:
movq$1,%rax
ret
但要小心,这只适用于香草OCaml的短路操作员。 即使是无害的更改,例如,
let(&&&=(&&&)
也会这样做,
jmp.L102
,也会被
call camlIs\u prime\u div\u check.
所取代

此外,这仅在呼叫位于短路操作员右侧时有效。左表达式为非尾部递归表达式。我已经对它进行了测试,实际上,将
div\u check
放在
&&
操作符的左侧将发出非尾部递归代码


如果您怀疑调用是否为tail,您可以始终向编译器添加
-annot
标志,并查看相应的
*.annot
文件,以获得
调用(tail)
注释。merlin中对此提供了一些工具支持,但我还没有弄清楚如何正确使用它。请记住,最终评判仍然是装配输出

i+i>n是否可以替换n mod i 0?只是为了表明短路调用是尾部递归的,函数的语义当然会改变。如果我加回
nmodi0
,编译器将发出一些键击,这些键击也将检查除法是否为零,否则,调用仍然是尾部递归的。
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