यह निर्भर करता है कि आप कितनी सख्ती से "पुनरावृत्ति" को परिभाषित करते हैं।
यदि हमें कॉल-स्टैक (या प्रोग्राम स्टेट को बनाए रखने के लिए जो भी तंत्र का उपयोग किया जाता है) को शामिल करने के लिए सख्ती से इसकी आवश्यकता होती है, तो हम इसे हमेशा किसी ऐसी चीज़ से प्रतिस्थापित कर सकते हैं जो इसे नहीं करता है। दरअसल, ऐसी भाषाएं जो स्वाभाविक रूप से पुनरावृत्ति के भारी उपयोग की ओर ले जाती हैं, में ऐसे कंपाइलर होते हैं जो टेल-कॉल ऑप्टिमाइज़ेशन का भारी उपयोग करते हैं, इसलिए आप जो लिखते हैं वह पुनरावर्ती है लेकिन जो आप चलाते हैं वह पुनरावृत्त है।
लेकिन एक मामले पर विचार करने देता है जहां हम एक पुनरावर्ती कॉल करते हैं और उस पुनरावर्ती कॉल के लिए एक पुनरावर्ती कॉल के परिणाम का उपयोग करते हैं।
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
if (m == 0)
return n+1;
if (n == 0)
return Ackermann(m - 1, 1);
else
return Ackermann(m - 1, Ackermann(m, n - 1));
}
पहला पुनरावर्ती कॉल पुनरावृत्त बनाना आसान है:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
restart:
if (m == 0)
return n+1;
if (n == 0)
{
m--;
n = 1;
goto restart;
}
else
return Ackermann(m - 1, Ackermann(m, n - 1));
}
हम फिर से सफाई कर सकते हैं दूर करने के goto
लिए दूर करने के लिए velociraptors और Dijkstra की छाया:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
while(m != 0)
{
if (n == 0)
{
m--;
n = 1;
}
else
return Ackermann(m - 1, Ackermann(m, n - 1));
}
return n+1;
}
लेकिन अन्य पुनरावर्ती कॉल को हटाने के लिए हमें कुछ कॉल के मूल्यों को एक स्टैक में संग्रहीत करना होगा:
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
Stack<BigInteger> stack = new Stack<BigInteger>();
stack.Push(m);
while(stack.Count != 0)
{
m = stack.Pop();
if(m == 0)
n = n + 1;
else if(n == 0)
{
stack.Push(m - 1);
n = 1;
}
else
{
stack.Push(m - 1);
stack.Push(m);
--n;
}
}
return n;
}
अब, जब हम स्रोत कोड पर विचार करते हैं, तो हमने निश्चित रूप से अपनी पुनरावर्ती पद्धति को पुनरावृति में बदल दिया है।
यह देखते हुए कि यह किसके लिए संकलित किया गया है, हमने कोड को बदल दिया है जो कॉल स्टैक का उपयोग कोड में पुनरावृत्ति को लागू करने के लिए करता है (और ऐसा नहीं किया गया कोड ऐसा करने के लिए जो कोड में बहुत छोटे मानों के लिए स्टैक-ओवरफ़्लो अपवाद को फेंक देगा जो केवल होगा वापसी के लिए एक लंबे समय तक ले लो [देखें कि मैं अपने एकरमैन फ़ंक्शन को स्टैक के अतिप्रवाह से कैसे रोक सकता हूं? कुछ और अनुकूलन के लिए जो इसे वास्तव में कई और संभावित इनपुटों के लिए वापस लाते हैं])।
यह देखते हुए कि आम तौर पर पुनरावृत्ति कैसे लागू की जाती है, हमने कोड को बदल दिया है जो कॉल-स्टैक का उपयोग कोड में करता है जो लंबित संचालन को रखने के लिए एक अलग स्टैक का उपयोग करता है। इसलिए हम तर्क दे सकते हैं कि यह अभी भी पुनरावर्ती है, जब उस निम्न स्तर पर विचार किया जाता है।
और उस स्तर पर, वास्तव में इसके आसपास कोई अन्य तरीके नहीं हैं। इसलिए यदि आप उस विधि को पुनरावर्ती मानते हैं, तो वास्तव में ऐसी चीजें हैं जो हम इसके बिना नहीं कर सकते। आम तौर पर हालांकि हम ऐसे कोड को पुनरावर्ती नहीं बताते हैं। शब्द पुनरावर्तन उपयोगी है क्योंकि यह दृष्टिकोण के एक निश्चित समूह को कवर करता है और हमें उनके बारे में बात करने का एक तरीका देता है, और हम अब उनमें से एक का उपयोग नहीं कर रहे हैं।
बेशक, यह सब आपके पास एक विकल्प है। दोनों भाषाएँ हैं जो पुनरावर्ती कॉलों को रोकती हैं, और ऐसी भाषाएँ जिनमें पुनरावृत्ति के लिए आवश्यक लूपिंग संरचनाओं का अभाव है।