68 lines
4.0 KiB
Markdown
68 lines
4.0 KiB
Markdown
---
|
||
title: TCO Tail Call Optimization
|
||
localeTitle: TCO Tail Call Optimization
|
||
---
|
||
## تحسين مكالمات الذيل (TCO)
|
||
|
||
يعتبر تحسين استدعاء الذيل ( **TCO** ) حلاً لمشكلة التكدس في المكدس عند القيام بالتكرار.
|
||
|
||
### المشكلة
|
||
|
||
يتم دفع كل مكالمة لوظيفة إلى رصة في ذاكرة الكمبيوتر. عند انتهاء الدالة ، يتم إفراغها من المكدس. في التكرار ، تستدعي الوظيفة نفسها بحيث تستمر في الإضافة إلى المكدس حتى تنتهي جميع تلك الوظائف. هناك ، بالطبع ، حد لهذا المكدس. عندما يكون هناك عدد كبير من الوظائف يسمى ، يتم إضافة الكثير من المكالمات إلى المكدس. عندما تكون المكدس ممتلئة ويتم استدعاء دالة ، يؤدي ذلك إلى **تجاوز سعة مكدس الذاكرة المؤقتة** نظرًا لأن المكدس ممتلئ بالفعل. لن تنتهي الدالة العودية وستؤدي إلى حدوث خطأ.
|
||
|
||
#### مثال
|
||
|
||
في ما يلي مثال على وظيفة مختبِس جافا سكريبت باستخدام التكرار **بدون** TCO:
|
||
|
||
` function fact(x) {
|
||
if (x <= 1) {
|
||
return 1;
|
||
} else {
|
||
return x * fact(x-1);
|
||
}
|
||
}
|
||
|
||
console.log(fact(10)); // 3628800
|
||
console.log(fact(10000)); // RangeError: Maximum call stack size exceeded
|
||
`
|
||
|
||
لاحظ أن تشغيل `fact` مع وسيطة 10000 سيؤدي إلى **تجاوز سعة مكدس** .
|
||
|
||
### استخدام TCO لحل المشكلة
|
||
|
||
لحل هذه المشكلة باستخدام "تحسين مكالمات الذيل" ، يجب أن تكون العبارة التي تستدعي فيها الوظيفة نفسها في موضع ذيل. موضع الذيل هو العبارة الأخيرة التي سيتم تنفيذها في وظيفة. لذلك ، يجب أن يكون استدعاء الدالة إلى نفسها آخر شيء يسمى قبل انتهاء الدالة.
|
||
|
||
في المثال السابق ، يتم تنفيذ عملية الضرب الأخيرة في عبارة `return x * fact(x-1)` ، لذلك لم تكن العملية النهائية للدالة. لذلك ، فهي ليست دعوة الذيل الأمثل. من أجل أن تكون مكالمة ذيل محسنة ، تحتاج إلى إجراء المكالمة نفسها العملية الأخيرة للوظيفة.
|
||
|
||
#### مثال
|
||
|
||
في ما يلي مثال على وظيفة مفاعل جافا سكريبت (ES5) باستخدام التكرار **مع** TCO.
|
||
|
||
` function fact(n) {
|
||
return factTCO(n, 1);
|
||
}
|
||
|
||
function factTCO(x, acc) {
|
||
if (x <= 1) {
|
||
return acc;
|
||
} else {
|
||
return factTCO(x-1, x*acc);
|
||
}
|
||
}
|
||
|
||
console.log(fact(10)); // 3628800
|
||
console.log(fact(10000)); // Infinity - Number too large, but unlike the unoptimized factorial, this does not result in stack overflow.
|
||
`
|
||
|
||
لاحظ أن تشغيل `fact` على 10000 هذه المرة لن **يؤدي إلى تجاوز سعة الرصة** عند _تشغيلها في مستعرض يدعم ES6_ لأن الاستدعاء إلى `factTCO` هو آخر عملية للدالة.
|
||
|
||
### لماذا هذا يعمل
|
||
|
||
عندما يلاحظ المحول البرمجي أو المفسر أن المكالمة الذاتية هي العملية الأخيرة للدالة ، فإنها تنبثق الوظيفة الحالية وتدفع المكالمة الذاتية إلى المكدس. بهذه الطريقة لا يتم تغيير حجم المكدس. لذلك ، لا تتكدس المكدس بسبب الدالة.
|
||
|
||
### ملاحظات
|
||
|
||
#### معلومات اكثر:
|
||
|
||
* [ما هو optmization دعوة الذيل؟](https://stackoverflow.com/questions/310974/what-is-tail-call-optimization) (ستاكوفيرفلوو)
|
||
* [تحسين استدعاء الذيل في ECMAScript 6](http://2ality.com/2015/06/tail-call-optimization.html) (2ality - مدونة Dr. Axel Rauschmayer) |