Evet, bazı diller ve derleyiciler yinelemeli mantığı yinelemesiz mantığa dönüştürür. Bu, kuyruk çağrısı optimizasyonu olarak bilinir - tüm yinelemeli çağrıların kuyruk çağrısı optimizasyonu olmadığını unutmayın. Bu durumda, derleyici formun bir işlevini tanır:
int foo(n) {
...
return bar(n);
}
Burada, dil, döndürülen sonucun başka bir işlevden kaynaklandığını tanıyabilir ve yeni bir yığın çerçeveli bir işlev çağrısını atlamaya dönüştürebilir.
Klasik faktöryel yöntemin farkına varın:
int factorial(n) {
if(n == 0) return 1;
if(n == 1) return 1;
return n * factorial(n - 1);
}
olduğu değil çünkü dönüş gerekli denetim kuyruk çağrı optimizatable.
Bu kuyruk çağrısını optimize edilebilir hale getirmek için,
int _fact(int n, int acc) {
if(n == 1) return acc;
return _fact(n - 1, acc * n);
}
int factorial(int n) {
if(n == 0) return 1;
return _fact(n, 1);
}
Bu kodu gcc -O2 -S fact.c
derlemek (derleyicide optimizasyonu etkinleştirmek için -O2 gereklidir, ancak -O3'ün daha fazla optimizasyonu ile bir insanın okuması zorlaşır ...)
_fact:
.LFB0:
.cfi_startproc
cmpl $1, %edi
movl %esi, %eax
je .L2
.p2align 4,,10
.p2align 3
.L4:
imull %edi, %eax
subl $1, %edi
cmpl $1, %edi
jne .L4
.L2:
rep
ret
.cfi_endproc
Bir segment görebilir .L4
, jne
yerine göre call
(yeni bir yığın çerçeveye sahip olan bir alt yordam çağrı yapar).
Bunun C ile yapıldığını lütfen unutmayın. Java'da kuyruk çağrı optimizasyonu zordur ve JVM uygulamasına bağlıdır - tail-recursion + java ve tail-recursion + optimizasyonu göz atmak için iyi etiket kümeleridir. Diğer JVM dilleri optimize kuyruk özyineleme daha iyi (gerektirir denemek Clojure (edebiliyoruz bulabilir tekrarlanmasını kuyruk çağrı optimize etmek için) veya scala).
return recursecall(args);
özyineleme için varsa , daha karmaşık şeyler açık bir yığın oluşturarak ve aşağı sarma ile mümkündür, ama onlar şüpheliyim