टेल कॉल

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

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

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

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

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

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

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

यहां,  और  दोनों कॉल टेल स्थिति में हैं। ऐसा इसलिए है क्योंकि उनमें से प्रत्येक क्रमशः if-शाखा के अंत में स्थित है, भले ही पहला   के शरीर के अंत में वाक्यात्मक रूप से नहीं है।

इस कोड में: पर कॉल  में टेल पोजीशन में है, लेकिन यह   या   में टेल पोजीशन में नहीं है, क्योंकि कॉल करने वाले को वापस लौटने से पहले रिटर्न वैल्यू का निरीक्षण या संशोधित करने की स्वीकृति देने के लिए नियंत्रण को वापस लौटना होगा।

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

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

यह प्रोग्राम एप्लिकेटिव-ऑर्डर मूल्यांकन मानता है। आंतरिक प्रक्रिया  स्वयं को नियंत्रण प्रवाह में अंतिम कहता है। यह एक दुभाषिया या संकलक को निष्पादन को पुनर्गठित करने की स्वीकृति देता है जो सामान्यतः इस तरह दिखेगा:

फैक्टोरियल को कॉल करें (4) 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 में सिएटल में एसीएम सम्मेलन में दिए गए एक पेपर में, गाइ एल. स्टील ने जीओटीओ और संरचित प्रोग्रामिंग पर बहस का सारांश दिया, और देखा कि किसी प्रक्रिया की पूंछ स्थिति में प्रक्रिया कॉल को नियंत्रण के सीधे हस्तांतरण के रूप में सबसे अच्छा माना जा सकता है। तथाकथित प्रक्रिया, आम तौर पर अनावश्यक स्टैक हेरफेर संचालन को समाप्त करती है। चूंकि इस तरह की "टेल कॉल" लिस्प में बहुत आम हैं, एक ऐसी भाषा जहां प्रक्रिया कॉल सर्वव्यापी हैं, अनुकूलन का यह रूप अन्य कार्यान्वयन की तुलना में प्रक्रिया कॉल की लागत को काफी कम कर देता है। स्टील ने तर्क दिया कि खराब ढंग से कार्यान्वित प्रक्रिया कॉलों ने एक कृत्रिम धारणा को जन्म दिया है कि प्रक्रिया कॉल की तुलना में GOTO सस्ता था। स्टील ने आगे तर्क दिया कि "सामान्य प्रक्रिया में कॉल को उपयोगी रूप से GOTO स्टेटमेंट के रूप में माना जा सकता है जो मापदंडों को भी पारित करता है, और समान रूप से [मशीन कोड] JUMP निर्देशों के रूप में कोडित किया जा सकता है", मशीन कोड स्टैक हेरफेर निर्देशों के साथ "एक अनुकूलन माना जाता है (बजाय) इसके विपरीत!)"।[2] स्टील ने सबूतों का हवाला दिया कि लिस्प में अच्छी तरह से अनुकूलित संख्यात्मक एल्गोरिदम तत्कालीन उपलब्ध वाणिज्यिक फोरट्रान कंपाइलरों द्वारा उत्पादित कोड की तुलना में तेजी से निष्पादित हो सकते हैं क्योंकि लिस्प में एक प्रक्रिया कॉल की लागत बहुत कम थी। स्कीम में, गेराल्ड जे सुसमैन के साथ स्टील द्वारा विकसित एक लिस्प बोली, टेल-कॉल उन्मूलन को किसी भी दुभाषिया में लागू करने की गारंटी है।

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

हालाँकि, भाषा कार्यान्वयन के लिए जो फ़ंक्शन तर्क और स्थानीय चर को कॉल स्टैक पर संग्रहीत करता है (जो कि कई भाषाओं के लिए डिफ़ॉल्ट कार्यान्वयन है, कम से कम हार्डवेयर स्टैक वाले सिस्टम पर, जैसे कि 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)