Zac*_*lle 6 ocaml tail-recursion ml sml
我(相信)以下函数定义是尾递归的:
fun is_sorted [] = true
| is_sorted [x] = true
| is_sorted (x::(y::xs)) =
if x > y
then false
else is_sorted (y::xs)
Run Code Online (Sandbox Code Playgroud)
琐碎的是,它等同于以下声明
fun is_sorted [] = true
| is_sorted [x] = true
| is_sorted (x::(y::xs)) =
(x <= y) andalso (is_sorted (y::xs))
Run Code Online (Sandbox Code Playgroud)
然而在这个版本中,最后一步是应用'andalso',所以它不是尾递归的.或者它似乎是这样,除了因为(至少是标准的)ML(NJ)使用短路评估,并且实际上/不是/最后一步.那么这个函数会有尾调用优化吗?还是有任何其他有趣的实例,其中明显使用尾递归的ML函数实际上得到优化?
注意
A andalso B
Run Code Online (Sandbox Code Playgroud)
相当于
if A then B else false
Run Code Online (Sandbox Code Playgroud)
SML语言定义甚至以这种方式定义它.因此,B 是在尾部位置.不需要花哨的优化.
如果我将你的第二个函数翻译成 OCaml,我会得到这个:
let rec is_sorted : int list -> bool = function
| [] -> true
| [_] -> true
| x :: y :: xs -> x < y && is_sorted xs
Run Code Online (Sandbox Code Playgroud)
这被 ocamlopt 编译为尾递归函数。生成的代码(x86_64)的本质是这样的:
.globl _camlAndalso__is_sorted_1008
_camlAndalso__is_sorted_1008:
.cfi_startproc
.L103:
cmpq $1, %rax
je .L100
movq 8(%rax), %rbx
cmpq $1, %rbx
je .L101
movq (%rbx), %rdi
movq (%rax), %rax
cmpq %rdi, %rax
jge .L102
movq 8(%rbx), %rax
jmp .L103
.align 2
.L102:
movq $1, %rax
ret
.align 2
.L101:
movq $3, %rax
ret
.align 2
.L100:
movq $3, %rax
ret
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
如您所见,此代码中没有递归调用,只有一个循环。
(但其他海报是正确的,OCaml 在复杂分析方面并没有做那么多。这个特殊的结果似乎很简单。)