ใช่บางภาษาและผู้ร้องเรียนจะแปลงตรรกะแบบเรียกซ้ำเป็นตรรกะแบบเรียกซ้ำ สิ่งนี้เรียกว่าการเพิ่มประสิทธิภาพการโทรแบบหาง - โปรดทราบว่าการโทรแบบเรียกซ้ำทั้งหมดไม่สามารถทำการโทรแบบหางได้ ในสถานการณ์นี้คอมไพเลอร์รับรู้ถึงฟังก์ชั่นของแบบฟอร์ม:
int foo(n) {
...
return bar(n);
}
ที่นี่ภาษาสามารถรับรู้ว่าผลลัพธ์ที่ส่งคืนมาเป็นผลลัพธ์จากฟังก์ชั่นอื่นและเปลี่ยนการเรียกใช้ฟังก์ชันด้วยกรอบสแต็กใหม่เป็นการกระโดด
ตระหนักดีว่าวิธีการแบบแฟกทอเรียล
int factorial(n) {
if(n == 0) return 1;
if(n == 1) return 1;
return n * factorial(n - 1);
}
คือไม่ optimizatable โทรหางเพราะของการตรวจสอบที่จำเป็นในการกลับมา
ในการทำให้การเรียก tail นี้สามารถปรับได้
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);
}
การคอมไพล์โค้ดนี้ด้วยgcc -O2 -S fact.c
(-O2 จำเป็นต้องเปิดใช้งานการปรับให้เหมาะสมในคอมไพเลอร์ แต่ด้วยการเพิ่มประสิทธิภาพที่ -O3 จะทำให้มนุษย์อ่านยาก ... )
_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
หนึ่งสามารถดูในส่วน.L4
ที่jne
มากกว่าcall
(ซึ่งไม่ได้โทร subroutine กับกองกรอบใหม่)
โปรดทราบว่าสิ่งนี้ทำด้วยการเพิ่มประสิทธิภาพ C. tail call ใน java นั้นยากและขึ้นอยู่กับการใช้งาน JVM - tail-recursion + javaและtail-recursion + optimizationเป็นชุดแท็กที่ดีในการเรียกดู คุณอาจพบว่าภาษา JVM อื่น ๆ สามารถปรับปรุงการเรียกซ้ำแบบหางให้ดีขึ้นได้ (ลอง clojure (ซึ่งต้องใช้การเพิ่มประสิทธิภาพการโทรซ้ำแบบหาง) หรือสกาล่า)
return recursecall(args);
สำหรับการเรียกซ้ำที่สิ่งที่ซับซ้อนมากขึ้นเป็นไปได้โดยการสร้างสแต็คที่ชัดเจนและคดเคี้ยวลง แต่ฉันสงสัยว่าพวกเขาจะ