Компиляторы семейства 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 (из Нью-Джерси) использует оценку короткого замыкания, фактически также / не / последний шаг. Так будет ли у этой функции оптимизация хвостового вызова? Или есть другие интересные случаи, когда функция ML, которая явно не использует хвостовую рекурсию, на самом деле оптимизируется?

2 ответа

Решение

Если я переведу вашу вторую функцию на 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 не делает ничего особенного на пути сложного анализа. Этот конкретный результат кажется довольно простым.)

Обратите внимание, что

A andalso B

эквивалентно

if A then B else false

Определение языка SML даже определяет его таким образом. Следовательно, B находится в хвостовой позиции. Не нужно модной оптимизации.

Другие вопросы по тегам