ML家族编译器是否对尾调用进行任何复杂的优化?

时间:2014-07-17 13:38:23

标签: ocaml sml tail-recursion ml

我(相信)以下函数定义是尾递归的:

fun is_sorted [] = true
  | is_sorted [x] = true
  | is_sorted (x::(y::xs)) =
    if x > y
       then false
       else is_sorted (y::xs)

平凡地说,它等同于以下声明

fun is_sorted [] = true
  | is_sorted [x] = true
  | is_sorted (x::(y::xs)) = 
    (x <= y) andalso (is_sorted (y::xs))

然而在这个版本中,最后一步是应用'andalso',所以它不是尾递归的。或者它似乎是这样,除了因为(至少是标准的)ML(NJ)使用短路评估,并且实际上/不是/最后一步。那么这个函数会有尾调用优化吗?  还是有任何其他有趣的实例,其中明显使用尾递归的ML函数实际上得到优化?

2 个答案:

答案 0 :(得分:6)

请注意

A andalso B

相当于

if A then B else false

SML语言定义甚至以这种方式定义它。因此,B 在尾部位置。不需要花哨的优化。

答案 1 :(得分:4)

如果我将你的第二个功能翻译成OCaml,我会得到这个:

let rec is_sorted : int list -> bool = function
| [] -> true
| [_] -> true
| x :: y :: xs -> x < y && is_sorted xs

这是由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

正如您所看到的,此代码中没有递归调用,只是一个循环。

(但其他海报是正确的,OCaml在复杂的分析方面做得并不多。这个特殊的结果看起来非常简单。)