टेल कॉल

कंप्यूटर विज्ञान में, टेल कॉल एक कॉल प्रक्रिया है जो किसी प्रक्रिया की अंतिम क्रिया के रूप में की जाती है। यदि किसी टेल कॉल का लक्ष्य एक ही प्रक्रिया है, तो प्रक्रिया को टेल कॉल प्रतिवर्तन कहा जाता है, जो प्रत्यक्ष रिकर्सन (कंप्यूटर विज्ञान) की एक विशेष स्थिति है। टेल रिकर्सन या टेल कॉल रिकर्सन विशेष रूप से उपयोगी है और इससे कार्यान्वयन में अनुकूलन करना प्रायः आसान होता है।

टेल कॉल को कॉल स्टैक में नया स्टैक फ़्रेम जोड़ने के अतिरिक्त प्रयुक्त किया जा सकता है। वर्तमान प्रक्रिया के अधिकांश फ़्रेम की अब आवश्यकता नहीं है और इसे टेल कॉल के फ़्रेम द्वारा प्रतिस्थापित किया जा सकता है, जिसे उपयुक्त के रूप में संशोधित किया जा सकता है प्रक्रियाओं के लिए ओवरले के समान, लेकिन फ़ंक्शन कॉल के लिए पुनः प्रोग्राम को तथाकथित प्रक्रिया पर जा सकता है। मानक कॉल अनुक्रम के अतिरिक्त ऐसे कोड को उत्पादन टेल-कॉल उन्मूलन या टेल-कॉल अनुकूलन कहा जाता है। टेल-कॉल उन्मूलन टेल स्थिति में प्रक्रिया कॉल को  कथन के रूप में कुशलतापूर्वक कार्यान्वित करने की स्वीकृति देता है, इस प्रकार कुशल संरचित प्रोग्रामिंग की स्वीकृति देता है। गाइ एल. स्टील के शब्दों में सामान्यतः प्रक्रिया कॉल को उपयोगी रूप से कथन के रूप में माना जा सकता है जो पैरामीटर भी पास करते हैं और समान रूप से मशीन कोड   निर्देशों के रूप में कोडित किया जा सकता है।

सभी प्रोग्रामिंग भाषाओं को टेल-कॉल उन्मूलन की आवश्यकता नहीं होती है। हालाँकि, कार्यात्मक प्रोग्रामिंग भाषाओं में टेल-कॉल उन्मूलन का दायित्व प्रायः भाषा मानक द्वारा किया जाता है, जिससे टेल रिकर्सन को समतुल्य लूप (कंप्यूटिंग) की समान मात्रा में मेमोरी का उपयोग करने की स्वीकृति प्राप्त होती है। टेल-रिकर्सिव कॉल की विशेष स्थिति मे जब कोई फ़ंक्शन स्वयं कॉल करता है, तो सामान्य टेल कॉल की तुलना में एलिमिनेशन को कॉल करने के लिए अधिक उत्तरदायी हो सकता है। जब भाषा कोड स्पष्ट रूप से सामान्य टेल कॉल का समर्थन नहीं करता है, तो कंपाइलर प्रायः सिबलिंग कॉल या टेल कॉल को ऐसे फ़ंक्शंस में प्रयुक्त कर सकता है जो कॉल के समान प्रकार के कोड को वापस करते हैं।

विवरण
जब किसी फ़ंक्शन को कॉल किया जाता है, तो कंप्यूटर को उस स्थान और वापसी एड्रेस को "याद" रखना चाहिए, ताकि कॉल पूरा होने के बाद वह परिणाम के साथ उस स्थान पर वापस आ सके। सामान्यतः यह जानकारी कॉल स्टैक पर साझा की जाती है, जो उनके द्वारा वर्णित कॉल स्थानों पर अभिगमन के समय के क्रम में वापसी स्थानों की एक सरल सूची है। टेल कॉल के लिए कॉल को याद रखने की कोई आवश्यकता नहीं होती है। इसके अतिरिक्त टेल-कॉल एलिमिनेशन इसे पास करने से पहले स्टैक फ्रेम में केवल न्यूनतम आवश्यक परिवर्तन करता है और टेल-कॉल फ़ंक्शन प्रत्यक्ष मूल कॉल पर वापस आ जाता है। स्रोत कोड में अन्य सभी कथनों के बाद टेल कॉल को शाब्दिक रूप से प्रकट होने की आवश्यकता नहीं होती है। केवल यह महत्वपूर्ण है कि कॉलिंग फ़ंक्शन टेल कॉल के शीघ्र बाद टेल कॉल के परिणाम को वापस कर दे, यदि कोई हो तो, क्योंकि अनुकूलन किए जाने पर कॉलिंग फ़ंक्शन को नष्ट कर दिया जाता है।

गैर-रिकर्सिव कॉल फ़ंक्शन के लिए यह सामान्यतः एक अनुकूलन है जो केवल अपेक्षाकृत समय और स्थान को सुरक्षित करता है क्योंकि कॉल करने के लिए कई अलग-अलग फ़ंक्शन उपलब्ध नहीं हैं। रिकर्सिव या पारस्परिक रूप से रिकर्सिव फ़ंक्शन के समय जहां रिकर्सन टेल कॉल के माध्यम से होता है। हालांकि स्टैक स्पेस और सहेजे गए रिटर्न टेल कॉल की संख्या बहुत महत्वपूर्ण हो सकती है क्योंकि एक फ़ंक्शन स्वयं को प्रत्यक्ष या अप्रत्यक्ष रूप से कॉल कर सकता है, जिससे एक नया कॉल स्टैक फ्रेम बन सकता है। टेल-कॉल उन्मूलन प्रायः अनंतस्पर्शी स्टैक स्पेस आवश्यकताओं को रैखिक O(n) या O(1) तक कम कर देता है। इस प्रकार कुछ प्रोग्रामिंग भाषाओं की मानक परिभाषाओं के लिए टेल-कॉल उन्मूलन की आवश्यकता होती है, जैसे स्कीम और एमएल (प्रोग्रामिंग भाषा) समूह की भाषाएं स्कीम भाषा की परिभाषा तर्क की स्थिति की सहज धारणा को शुद्ध रूप से औपचारिक बनाती है। यह निर्दिष्ट करके कि कौन से वाक्यात्मक तर्क के संदर्भ में परिणाम प्राप्त करने की स्वीकृति देते हैं। टेल-कॉल उन्मूलन के कारण एक ही समय में असीमित संख्या में टेल कॉल को सक्रिय करने की स्वीकृति देने वाले कार्यान्वयन को 'उपयुक्त रूप से टेल रिकर्सिव' भी कहा जा सकता है।

एड्रेस और निष्पादन दक्षता के अतिरिक्त टेल-कॉल उन्मूलन कार्यात्मक प्रोग्रामिंग में महत्वपूर्ण है जिसे निरंतरता-पासिंग शैली (सीपीएस) के रूप में जाना जाता है, जो शीघ्र ही स्टैक एड्रेस से बाहर हो जाती है।

वाक्यविन्यास रूप
किसी फ़ंक्शन के वाक्यात्मक अंत से ठीक पहले एक टेल कॉल स्थित हो सकती है: यहां  और   दोनों कॉल हैं, लेकिन   अंतिम डेटा है जिसे प्रक्रिया लौटने से पहले निष्पादित करती है और इस प्रकार तर्क की स्थिति में होती है। हालाँकि, सभी टेल कॉल आवश्यक रूप से प्रक्रिया के वाक्यात्मक अंत में स्थित नहीं होते हैं:

यहां,  और  दोनों कॉल टेल स्थिति में हैं। ऐसा इसलिए है क्योंकि उनमें से प्रत्येक क्रमशः  -शाखा के अंत में स्थित है, इस कोड में पहला   एल्गोरिथम के अंत में वाक्यात्मक रूप से नहीं है: यहाँ पर  कॉल   में टेल कॉल स्थिति में है, लेकिन यह   या   में टेल कॉल स्थिति में नहीं है क्योंकि कॉल करने वाले फंक्शन को वापस लौटने से पहले रिटर्न मान का निरीक्षण या संशोधित करने की स्वीकृति देने के लिए नियंत्रण को वापस लौटना होता है।

उदाहरण: फंक्शन
निम्नलिखित प्रोग्राम स्कीम प्रोग्रामिंग भाषा का एक उदाहरण है:

यह टेल-रिकर्सिव शैली में नहीं लिखा गया है, क्योंकि गुणन फ़ंक्शन ( * ) टेल की स्थिति में है। इसकी तुलना निम्न से की जा सकती है:

यह प्रोग्राम आनुप्रायोगिक अनुक्रम का मूल्यांकन करता है। आंतरिक प्रक्रिया  स्वयं को नियंत्रण डेटा में अंतिम कहता है। यह एक अनुवादक या संकलक को निष्पादन को पुनर्गठित करने की स्वीकृति देता है जो सामान्यतः इस प्रकार प्रदर्शित होता है: call factorial (4) call fact-iter (1 4) call fact-iter (4 3) call fact-iter (12 2) call fact-iter (24 1) return 24 return 24 return 24 return 24 return 24 एड्रेस और समय दोनों के संदर्भ में अधिक एल्गोरिथम दक्षता संस्करण: call factorial (4) call fact-iter (1 4) replace arguments with (4 3) replace arguments with (12 2) replace arguments with (24 1) return 24 return 24 यह पुनर्गठन भंडारण को बचाता है क्योंकि कॉलिंग फ़ंक्शन के एड्रेस को छोड़कर किसी भी स्थिति को स्टैक या हीप पर साझा करने की आवश्यकता नहीं होती है और  के लिए कॉल स्टैक फ्रेम को मध्यवर्ती परिणाम भंडारण के लिए पुन: उपयोग किया जाता है। इसका तात्पर्य यह भी है कि प्रोग्रामर को अत्यधिक रिकर्सन के लिए स्टैक या हीप भंडारण नष्ट होने के विषय में चिंता करने की आवश्यकता नहीं होती है। विशिष्ट कार्यान्वयन में टेल-रिकर्सिव फ़ंक्शन अन्य फ़ंक्शन की तुलना में एक स्थिर फ़ंक्शन द्वारा अपेक्षाकृत तीव्र होता है।

कार्यात्मक भाषाओं में कार्य करने वाले कुछ प्रोग्रामर रिकर्सिव होने के लिए रिकर्सिव कोड को फिर से लिखेंगे ताकि वे इस सुविधा का लाभ प्राप्त कर सकें। इसके लिए प्रायः एक संचायक तर्क जोड़ने की आवश्यकता होती है ( उपरोक्त उदाहरण में) फ़ंक्शन के लिए कुछ स्थितियों में (जैसे फ़िल्टरिंग सूचियां) और कुछ भाषाओं में पूर्ण तर्क रिकर्सन के लिए एक फ़ंक्शन की आवश्यकता हो सकती है जो पहले लिखने के लिए पूरी तरह कार्यात्मक थी ताकि इनसे अन्य वेरिएबल में संग्रहीत संदर्भों को परिवर्तित किया आ सकता है।

टेल रिकर्सन मॉड्यूल कॉन्स
टेल रिकर्सन मोडुलो कॉन्स, प्रोलॉग के संकलन के संदर्भ में डेविड एच. डी. वॉरेन द्वारा प्रारम्भ की गई टेल-रिकर्सन अनुकूलीकरण का एक सामान्यीकरण है, जिसे स्पष्ट रूप से एक बार प्रयुक्त की गई भाषा के रूप में देखा जाता है। इसे 1974 में डैनियल पी. फ्रीडमैन और डेविड एस. वाइज द्वारा एक एलआईएसपी संकलन तकनीक के रूप में वर्णित किया गया था। हालांकि इसका कोई नाम नहीं दिया गया था जैसा कि नाम से पता चलता है, यह तब प्रयुक्त होता है जब रिकर्सिव कॉल के बाद निष्पादित करने के लिए एकमात्र संचालन उससे लौटाई गई सूची के सामने एक ज्ञात मान जोड़ना होता है या सामान्य रूप से सरल डेटा-निर्माण कार्यों की निरंतर संख्या निष्पादित करना होता है। इस प्रकार यह कॉल उक्त कॉन्स संचालन ("मॉड्यूलो") के लिए एक टेल कॉल होती है लेकिन रिकर्सिव कॉल से बाहर निकलने पर किसी सूची के प्रारम्भ में एक मान उपसर्ग लगाना, रिकर्सिव कॉल में प्रवेश पर बढ़ती सूची के अंत में इस मान को जोड़ने के समान है। इस प्रकार सूची को एक अन्य प्रभाव के रूप में बनाना, जैसे कि एक में अंतर्निहित संचायक पैरामीटर निम्नलिखित प्रोलॉग विभाजन इस अवधारणा को दर्शाता है:

उदाहरण कोड
इस प्रकार टेल-रिकर्सिव अनुवाद में ऐसी कॉल को पहले एक नई सूची नोड बनाने और उसके  सूची को प्रयुक्त करने में परिवर्तित कर दिया जाता है और फिर पॉइंटर के साथ नोड के   सूची को तर्क के रूप में टेल कॉल करके रिकर्सिव रूप से भरा जाता है। वही प्रभाव तब प्राप्त होता है जब रिकर्सन को एक वास्तविक मूल्यांकन किए गए डेटा  निर्माता के अंतर्गत संरक्षित किया जाता है, जो हास्केल जैसी लैज़िली प्रोग्रामिंग भाषाओं में स्वचालित रूप से प्राप्त होता है।

सी प्रोग्रामिंग के उदाहरण
निम्नलिखित खंड सी प्रोग्रामिंग में एक रिकर्सिव फ़ंक्शन को परिभाषित करता है जो तुलना के लिए टिप्पणियों के रूप में कुछ समकक्ष योजना और प्रोलॉग कोड के साथ एक लिंक की गई सूची को प्रतिलिपित करता है: इस रूप में फ़ंक्शन टेल रिकर्सिव नहीं है क्योंकि रिकर्सिव कॉल के बाद शेष इनपुट सूची को प्रतिलिपित करने के बाद नियंत्रण कॉलर पर वापस आ जाता है। यद्यपि इसे अन्य को प्रतिलिपित करने से पहले हेड नोड आवंटित करना था, फिर भी इसे कॉल के बाद रिकर्सिव कॉल के परिणाम को  सूची में प्रयुक्त करना होता है। तो फ़ंक्शन लगभग तर्क रिकर्सिव है। वॉरेन की विधि   सूची को रिकर्सिव कॉल में भरने की आवश्यकता को आगे बढ़ाती है जो इस प्रकार टेल कॉल बन जाती है। कोड को सरल बनाने के लिए सेंटिनल हेड नोड का उपयोग किया जाता है:

कॉल प्राप्तकर्ता अब बढ़ती हुई सूची के अंत में जुड़ जाता है, न कि कॉल करने वाले को लौटाई गई सूची की प्रारम्भ में जोड़ा जाता है। कार्य अब सूची के प्रारम्भ से आगे की ओर किया जाता है, रिकर्सिव कॉल से पहले, जो रिकर्सिव कॉल के अपना परिणाम लौटाने के बाद सूची के अंत से पीछे की अतिरिक्त आगे बढ़ता है। इस प्रकार यह संचय पैरामीटर तकनीक के समान है, जो रिकर्सिव गणना को पुनरावृत्त में परिवर्तित कर देता है।इस तकनीक के लिए विशिष्ट रूप से निष्पादन कॉल स्टैक पर एक पैरेंट कॉल फ़्रेम बनाया जाता है, जिसे टेल-रिकर्सिव कैली टेल-कॉल अनुकूलीकरण सम्मिलित होने पर अपने स्वयं के कॉल फ्रेम के रूप में पुन: उपयोग कर सकता है। टेल-रिकर्सिव कार्यान्वयन को अब एक संचित लूप (कंप्यूटिंग) के रूप में स्पष्ट रूप से पुनरावृत्त कार्यान्वयन में परिवर्तित किया जा सकता है:

इतिहास
1977 में सिएटल में एसीएम सम्मेलन में दिए गए एक पेपर में गाइ एल. स्टील ने जीओटीओ और संरचित प्रोग्रामिंग पर चर्चा का सारांश दिया और देखा कि किसी प्रक्रिया की तर्क स्थिति में प्रक्रिया कॉल को नियंत्रण के सीधे हस्तांतरण के रूप में सबसे अच्छा माना जा सकता है। तथाकथित प्रक्रिया सामान्यतः अनावश्यक स्टैक हस्तांतरण संचालन को समाप्त करती है। चूंकि इस प्रकार की "टेल कॉल" लिस्प में बहुत सामान्य हैं, एक ऐसी भाषा जहां प्रक्रिया कॉल सर्वव्यापी हैं, अनुकूलन का यह रूप अन्य कार्यान्वयन की तुलना में प्रक्रिया कॉल की लागत को अपेक्षाकृत कम कर देता है। स्टील ने तर्क दिया कि अस्पष्ट रूप से कार्यान्वित प्रक्रिया कॉलों ने एक कृत्रिम धारणा को जन्म दिया है कि प्रक्रिया कॉल की तुलना में  अपेक्षाकृत कम उपयोगी था। स्टील ने आगे तर्क दिया कि "सामान्य प्रक्रिया में कॉल को उपयोगी रूप से   कथन के रूप में माना जा सकता है जो मापदंडों को भी पारित करता है और समान रूप से मशीन कोड निर्देशों के रूप में कोडित किया जा सकता है", मशीन कोड स्टैक हस्तांतरण निर्देशों के साथ "एक अनुकूलन माना जाता है। इसके विपरीत स्टील ने प्रमाणों को प्रस्तुत किया कि लिस्प में अच्छी तरह से अनुकूलित संख्यात्मक एल्गोरिदम शीघ्र उपलब्ध वाणिज्यिक फोरट्रान कंपाइलरों द्वारा उत्पादित कोड की तुलना में तीव्रता से निष्पादित हो सकते हैं क्योंकि लिस्प में एक प्रक्रिया कॉल की लागत अपेक्षाकृत बहुत कम थी। स्कीम भाषा में गेराल्ड जे सुसमैन के साथ स्टील द्वारा विकसित एक लिस्प भाषा टेल-कॉल उन्मूलन को किसी भी अनुवादक में प्रयुक्त करने का दायित्व करती है।

कार्यान्वयन विधियाँ
टेल रिकर्सन कुछ उच्च-स्तरीय भाषाओं, विशेष रूप से कार्यात्मक और तर्क प्रोग्रामिंग भाषाओं और लिस्प प्रोग्रामिंग भाषा परिवार के सदस्यों के लिए महत्वपूर्ण है। इन भाषाओं में, पुनरावृत्ति को प्रयुक्त करने के लिए टेल रिकर्सन सबसे अधिक इस्तेमाल किया जाने वाला तरीका (और कभी-कभी उपलब्ध एकमात्र तरीका) है। योजना के भाषा विनिर्देश के लिए आवश्यक है कि टेल कॉल को अनुकूलित किया जाए ताकि स्टैक में वृद्धि न हो। टेल कॉल को पर्ल में स्पष्ट रूप से "गोटो" स्टेटमेंट के एक प्रकार के साथ किया जा सकता है, जो एक फ़ंक्शन नाम लेता है:

हालाँकि, भाषा कार्यान्वयन के लिए जो फ़ंक्शन तर्क और स्थानीय वेरिएबल को कॉल स्टैक पर संग्रहीत करता है (जो कि कई भाषाओं के लिए डिफ़ॉल्ट कार्यान्वयन है, कम से कम हार्डवेयर स्टैक वाले सिस्टम पर, जैसे कि x86), सामान्यीकृत टेल-कॉल अनुकूलन को प्रयुक्त करना (पारस्परिक सहित) टेल रिकर्सन) एक समस्या प्रस्तुत करता है: यदि कैली के सक्रियण रिकॉर्ड का आकार कॉल करने वाले से भिन्न है, तो स्टैक फ्रेम की अतिरिक्त सफाई या आकार बदलने की आवश्यकता हो सकती है। इन मामलों के लिए, टेल रिकर्सन को अनुकूलित करना तुच्छ रहता है, लेकिन सामान्य टेल-कॉल ऑप्टिमाइज़ेशन को कुशलता से प्रयुक्त करना कठिन हो सकता है।

उदाहरण के लिए, जावा वर्चुअल मशीन (जेवीएम) में, टेल-रिकर्सिव कॉल्स को समाप्त किया जा सकता है (क्योंकि यह मौजूदा कॉल स्टैक का पुन: उपयोग करता है), लेकिन सामान्य टेल कॉल्स नहीं हो सकती हैं (क्योंकि यह कॉल स्टैक को बदल देता है)। परिणामस्वरूप, स्काला (प्रोग्रामिंग भाषा) जैसी कार्यात्मक भाषाएं जो जेवीएम को लक्षित करती हैं, प्रत्यक्ष टेल रिकर्सन को कुशलतापूर्वक प्रयुक्त कर सकती हैं, लेकिन पारस्परिक टेल रिकर्सन को नहीं।

जीएनयू कंपाइलर संग्रह,, एलएलवीएम/क्लैंग और इंटेल सी कंपाइलर सुइट्स सी और अन्य भाषाओं के लिए उच्च अनुकूलन स्तरों पर या जब  विकल्प पारित हो जाता है, टेल-कॉल अनुकूलन करते हैं।  हालाँकि दिया गया भाषा सिंटैक्स स्पष्ट रूप से इसका समर्थन नहीं कर सकता है, लेकिन कंपाइलर यह अनुकूलन कर सकता है जब भी वह यह निर्धारित कर सकता है कि कॉलर और कैली के लिए रिटर्न प्रकार समतुल्य हैं और दोनों फ़ंक्शन के लिए पारित तर्क प्रकार या तो समान हैं, या समान राशि की आवश्यकता है कॉल स्टैक पर कुल संग्रहण स्थान का।

विभिन्न कार्यान्वयन विधियाँ उपलब्ध हैं।

असेंबली में
टेल कॉल को प्रायः कार्यात्मक प्रोग्रामिंग और तर्क प्रोग्रामिंग भाषाओं के दुभाषियों और कंपाइलरों द्वारा पुनरावृत्ति के अधिक कुशल रूपों के लिए अनुकूलित किया जाता है। उदाहरण के लिए, स्कीम प्रोग्रामर सामान्यतः टेल पोजीशन में प्रक्रियाओं के लिए कॉल के रूप में जबकि लूप व्यक्त करते हैं और अधिक कुशल जंप निर्देशों के साथ टेल कॉल को प्रतिस्थापित करने के लिए स्कीम कंपाइलर या अनुवादक पर भरोसा करते हैं।

सीधे असेंबली उत्पन्न करने वाले कंपाइलरों के लिए, टेल-कॉल उन्मूलन आसान है: स्टैक पर पैरामीटर्स को ठीक करने के बाद, कॉल ऑपकोड को जंप वन से बदलना पर्याप्त है। एक कंपाइलर के नजरिए से, ऊपर दिए गए पहले उदाहरण को शुरू में छद्म-असेंबली भाषा में अनुवादित किया गया है (वास्तव में, यह वैध x86 असेंबली भाषा है): टेल-कॉल एलिमिनेशन अंतिम दो पंक्तियों को एक ही जंप निर्देश से बदल देता है: प्रक्रिया के बाद  पूरा हो जाता है, फिर यह सीधे रिटर्न पते पर वापस आ जाएगा , अनावश्यक को छोड़ देना   कथन।

सामान्यतः, बुलाए जा रहे प्रक्रिया्स को मापदंडों के साथ आपूर्ति करने की आवश्यकता होती है। इस प्रकार उत्पन्न कोड को यह सुनिश्चित करने की आवश्यकता है कि टेल-कॉल किए गए प्रक्रिया पर जाने से पहले ए के लिए कॉल फ्रेम ठीक से सेट किया गया है। उदाहरण के लिए, ऐसे प्लेटफ़ॉर्म पर जहां कॉल स्टैक में न केवल रिटर्न एड्रेस होता है, बल्कि प्रक्रिया के पैरामीटर भी होते हैं, कंपाइलर को कॉल स्टैक को समायोजित करने के लिए निर्देश प्रारम्भ करने की आवश्यकता हो सकती है। कोड के लिए ऐसे मंच पर: function foo(data1, data2) B(data1) return A(data2) (कहाँ  और   पैरामीटर हैं) एक कंपाइलर इसका अनुवाद इस प्रकार कर सकता है: एक टेल-कॉल ऑप्टिमाइज़र तब कोड को इसमें बदल सकता है: यह कोड निष्पादन गति और स्टैक स्पेस के उपयोग दोनों के मामले में अधिक कुशल है।

ट्रैम्पोलिनिंग के माध्यम से
चूँकि कई स्कीम कंपाइलर C को एक मध्यवर्ती लक्ष्य कोड के रूप में उपयोग करते हैं, टेल रिकर्सन को स्टैक को बढ़ाए बिना C में एन्कोड किया जाना चाहिए, भले ही C कंपाइलर टेल कॉल को ऑप्टिमाइज़ न करता हो। कई कार्यान्वयन ट्रैम्पोलिन (कंप्यूटर) नामक उपकरण का उपयोग करके इसे प्राप्त करते हैं, कोड का एक टुकड़ा जो बार-बार फ़ंक्शन को कॉल करता है। सभी कार्यों को ट्रैम्पोलिन के माध्यम से दर्ज किया जाता है। जब किसी फ़ंक्शन को सीधे कॉल करने और फिर परिणाम लौटाने के अतिरिक्त किसी अन्य को टेल-कॉल करना होता है, तो यह कॉल किए जाने वाले फ़ंक्शन का पता और कॉल पैरामीटर ट्रैम्पोलिन (जहां से इसे स्वयं कॉल किया गया था) पर वापस लौटाता है, और ट्रैम्पोलिन निर्दिष्ट मापदंडों के साथ इस फ़ंक्शन को कॉल करने का ध्यान रखता है। यह सुनिश्चित करता है कि सी स्टैक नहीं बढ़ता है और पुनरावृत्ति अनिश्चित काल तक प्रारम्भ रह सकती है।

उन भाषाओं में उच्च-क्रम के फ़ंक्शंस का उपयोग करके ट्रैम्पोलिन को प्रयुक्त करना संभव है जो उनका समर्थन करते हैं, जैसे कि ग्रूवी (प्रोग्रामिंग भाषा), विज़ुअल बेसिक .NET और सी शार्प (प्रोग्रामिंग भाषा)|सी#।

सभी फ़ंक्शन कॉल के लिए ट्रैम्पोलिन का उपयोग करना सामान्य सी फ़ंक्शन कॉल की तुलना में अधिक महंगा है, इसलिए कम से कम एक स्कीम कंपाइलर, चिकन, एंड्रयू अपेल के एक अप्रकाशित सुझाव से हेनरी बेकर (कंप्यूटर वैज्ञानिक) द्वारा वर्णित तकनीक का उपयोग करता है जिसमें सामान्य सी कॉल का उपयोग किया जाता है लेकिन प्रत्येक कॉल से पहले स्टैक आकार की जाँच की जाती है। जब स्टैक अपने अधिकतम अनुमत आकार तक पहुंच जाता है, तो स्टैक पर मौजूद वस्तुओं को सभी लाइव डेटा को एक अलग ढेर में ले जाकर चेनी एल्गोरिदम का उपयोग करके कवेरिएबला एकत्र किया जाता है। इसके बाद, स्टैक को खोल दिया जाता है ("पॉप किया गया") और प्रोग्राम कवेरिएबला संग्रहण से ठीक पहले सहेजी गई स्थिति से फिर से शुरू हो जाता है। बेकर कहते हैं, "एपेल की विधि कभी-कभी एम्पायर स्टेट बिल्डिंग से कूदकर बड़ी संख्या में छोटे ट्रैम्पोलिन को उछालने से बचाती है।" कवेरिएबला संग्रहण यह सुनिश्चित करता है कि पारस्परिक तर्क पुनरावृत्ति अनिश्चित काल तक प्रारम्भ रह सकती है। हालाँकि, इस दृष्टिकोण के लिए आवश्यक है कि कोई भी C फ़ंक्शन कॉल कभी वापस न आए, क्योंकि इसकी कोई गारंटी नहीं है कि इसके कॉलर का स्टैक फ्रेम अभी भी मौजूद है, इसलिए इसमें प्रोग्राम कोड का बहुत अधिक नाटकीय आंतरिक पुनर्लेखन सम्मिलित है: निरंतरता-पासिंग शैली।

थोड़ी देर के कथन से संबंध
टेल रिकर्सन को जबकि कथन से संबंधित किया जा सकता है, उदाहरण के लिए रूपांतरित करके एक स्पष्ट पुनरावृत्ति procedure foo(x) if p(x) return bar(x) else return foo(baz(x))

procedure foo(x) while true if p(x) return bar(x) else x ← baz(x) जहां x एक टपल हो सकता है जिसमें एक से अधिक वेरिएबल सम्मिलित हों: यदि ऐसा है, तो असाइनमेंट (कंप्यूटर विज्ञान) x ← baz(x) को प्रयुक्त करने में सावधानी बरतनी चाहिए ताकि निर्भरता का सम्मान किया जा सके। किसी को सहायक वेरिएबल पेश करने या स्वैप (कंप्यूटर विज्ञान) निर्माण का उपयोग करने की आवश्यकता हो सकती है।

सामान्यतः अधिक, procedure foo(x) if p(x) return bar(x) else if q(x) return baz(x) ...  else if r(x) return foo(qux(x)) ...  else return foo(quux(x)) में परिवर्तित किया जा सकता है procedure foo(x) while true if p(x) return bar(x) else if q(x) return baz(x) ...    else if r(x) x ← qux(x) ...    else x ← quux(x) उदाहरण के लिए, यह जूलिया (प्रोग्रामिंग भाषा) प्रोग्राम एक गैर-तर्क रिकर्सिव परिभाषा देता है  भाज्य का: function factorial(n) if n == 0 return 1 else return n * factorial(n - 1) end end वास्तव में  कॉल को   में लपेटता है। लेकिन इसे एक एक्युमुलेटर नामक तर्क जोड़कर टेल-रिकर्सिव परिभाषा में बदला जा सकता है।

यह जूलिया प्रोग्राम फैक्टोरियल की टेल-रिकर्सिव परिभाषा  देता है: function factorial(n::Integer, a::Integer) if n == 0: return a  else return factorial(n - 1, n * a)  end end function factorial(n::Integer) return factorial(n, 1) end यह जूलिया प्रोग्राम एक पुनरावृत्तीय परिभाषा देता है  भाज्य का:

भाषा समर्थन

 * क्लोजर (प्रोग्रामिंग भाषा) – क्लोजर के पास है  विशेष रूप.
 * सामान्य लिस्प – कुछ कार्यान्वयन गति के लिए अनुकूलन करते हुए संकलन के दौरान टेल-कॉल अनुकूलन करते हैं
 * अमृत (प्रोग्रामिंग भाषा) – एलिक्सिर टेल-कॉल ऑप्टिमाइज़ेशन प्रयुक्त करता है, जैसा कि वर्तमान में BEAM VM को लक्षित करने वाली सभी भाषाएँ कर रही हैं।
 * एल्म (प्रोग्रामिंग भाषा) – हाँ
 * एर्लांग (प्रोग्रामिंग भाषा) – हाँ
 * एफ शार्प (प्रोग्रामिंग भाषा)|एफ# – F# जहां संभव हो वहां डिफ़ॉल्ट रूप से TCO प्रयुक्त करता है
 * जाओ (प्रोग्रामिंग भाषा) – कोई सहायता नहीं
 * हास्केल (प्रोग्रामिंग भाषा) – हाँ
 * जावास्क्रिप्ट – ईसीएमएस्क्रिप्ट 6.0 अनुरूप इंजनों में टेल कॉल होनी चाहिए जिसे अब Safari (ब्राउज़र)/WebKit पर प्रयुक्त किया गया है लेकिन V8 और स्पाइडरमंकी द्वारा अस्वीकार कर दिया गया
 * कोटलिन (प्रोग्रामिंग भाषा) – है  कार्यों के लिए संशोधक
 * लुआ (प्रोग्रामिंग भाषा) – भाषा की परिभाषा के अनुसार टेल रिकर्सन आवश्यक है
 * उद्देश्य सी – -O1 (या उच्चतर) विकल्प निर्दिष्ट होने पर कंपाइलर टेल कॉल को अनुकूलित करता है लेकिन स्वचालित संदर्भ गणना (एआरसी) द्वारा जोड़े गए कॉल से यह आसानी से परेशान हो जाता है।
 * ओकैमल – हाँ
 * पर्ल (प्रोग्रामिंग भाषा) – गोटो कथन के एक प्रकार के साथ स्पष्ट जो एक फ़ंक्शन नाम लेता है:
 * प्योरस्क्रिप्ट – हाँ
 * पायथन (प्रोग्रामिंग भाषा) – स्टॉक पायथन कार्यान्वयन टेल-कॉल ऑप्टिमाइज़ेशन नहीं करता है, हालांकि ऐसा करने के लिए एक तृतीय-पक्ष मॉड्यूल उपलब्ध है। भाषा के आविष्कारक गुइडो वैन रोसुम का तर्क है कि ढेर के निशान को टेल-कॉल उन्मूलन द्वारा बदल दिया जाता है जिससे डिबगिंग कठिन हो जाती है, और पसंद करते हैं कि प्रोग्रामर इसके अतिरिक्त स्पष्ट पुनरावृत्ति का उपयोग करते हैं
 * रैकेट (प्रोग्रामिंग भाषा) – हाँ
 * जंग (प्रोग्रामिंग भाषा) – टेल-कॉल अनुकूलन सीमित परिस्थितियों में किया जा सकता है, लेकिन इसकी गारंटी नहीं है
 * स्काला (प्रोग्रामिंग भाषा) – टेल-रिकर्सिव फ़ंक्शंस स्वचालित रूप से कंपाइलर द्वारा अनुकूलित होते हैं। ऐसे कार्यों को वैकल्पिक रूप से a से भी चिह्नित किया जा सकता है  एनोटेशन, जो इसे एक संकलन त्रुटि बनाता है यदि फ़ंक्शन टेल रिकर्सिव नहीं है
 * योजना (प्रोग्रामिंग भाषा) – भाषा परिभाषा के अनुसार आवश्यक
 * टी.सी.एल – टीसीएल 8.6 के बाद से, टीसीएल के पास टेलकॉल कमांड है
 * ज़िग (प्रोग्रामिंग भाषा) – हाँ

यह भी देखें

 * मूल्यों की पुनरावृत्ति
 * रिकर्सन (कंप्यूटर विज्ञान)
 * इनलाइन विस्तार
 * पत्ता प्रक्रिया
 * कोरकर्शन

संदर्भ
Recursividade (ciência da computação) Recursión (ciencias de computación)