2015-08-23 3 views
13

different how-tos अमृत प्रोग्रामिंग पर की A number का मानना ​​है कि राज्य भंडारण या अनंत लूप चल रहा एक एजेंट या कार्य, में बंद या समारोह है कि राज्य की जरूरत के अनंत प्रत्यावर्तन द्वारा डेटा कताई द्वारा मुहावरे या तो किया जाता है व्यक्त करते हैं। वे किसी भी सीमा का उल्लेख नहीं करते हैं कि रिकर्सन कितना गहरा हो सकता है या कोई अन्य चेतावनी।क्या एलिक्सीर अनंत रिकर्सन कभी ढेर से बहती है?

"अमृत ढेर अतिप्रवाह" सिर्फ इस वेबसाइट पर हिट में परिणाम के लिए खोज के बाद से, मुझे अस्पष्टता को हटा दें और यहाँ पूछना है: क्या कार्यान्वयन गारंटी देता है कि की एक विधि के रूप में अनंत प्रत्यावर्तन 'पाशन' जीता सुनिश्चित करने के लिए अमृत में देखते हैं नतीजतन एक ढेर ओवरफ्लो में, विशेष रूप से जब राज्य की जानकारी रास्ते में चारों ओर ले जाया जा रहा है?

+7

: _ "अमृत/Erlang में, इस तरह प्रत्यावर्तन एक ढेर अतिप्रवाह कारण नहीं है, क्योंकि दोनों भाषाओं तथाकथित की विशेष हैंडलिंग है" पूंछ कॉल "जो होगा, पर एक बाइट कोड स्तर, एक कूद/गोटो निर्देशों में परिवर्तित हो जाएं। परिणामस्वरूप, यह कोड बस एक अंतहीन पाश चलाता है। "_ –

+1

धन्यवाद। मैं इस प्रश्न को उपयोगी रखने के लिए अपने शब्द को स्पष्ट कर दूंगा। –

+5

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

उत्तर

15

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

एक पूंछ कॉल है क्या करने के लिए के रूप में कुछ सूक्ष्म बारीकियों रहे हैं। आइए कुछ उदाहरण देखें। सबसे सरल एक है:

def foo do 
    # ... 

    bar(...) # tail call -> nothing is pushed to the stack 
end 

TCO भी सशर्त भाव के लिए लागू होंगे:

def foo do 
    # ... 

    if (...) do 
    # ... 
    bar(...)   # tail call 
    else 
    # ... 
    baz(...)   # tail call 
    end 
end 

यह काम करता है क्योंकि फिर से आखिरी बात एक समारोह करता है एक समारोह की एक मंगलाचरण है। if का परिणाम या तो bar या baz का परिणाम इतना ढेर पर कुछ भी पुश करने के लिए कोई जरूरत नहीं है।

इसके विपरीत, फोन करने वाले समारोह एक और कार्यप्रणाली को कॉल करने के बाद कुछ है, तो यह नहीं एक पूंछ कॉल है, और TCO नहीं होगा:

def foo do 
    # ... 

    # Not a tail call since we're doing something after bar returns 
    # (increment the result by 1) 
    1 + bar(...)  
end 

TCO try में समारोह बुला रहा है को तोड़ने का एक और उदाहरण:

def foo do 
    try do 
    bar(...) # not a tail call 
    rescue 
    # ... 
    end 
end 

यह भी उल्लेख है कि TCO की वजह से आप स्टैक ट्रेस में कुछ कार्यों को नहीं देखेंगे जब एक अपवाद तब होता है लायक है:

def foo do 
    # ... 
    bar(...) # at this point foo "disappears" from stack trace 
end 

def bar(...) do 
    # ... 
    raise("error") 
end 

इस त्रुटि के ढेर डंप में foo शामिल नहीं होगा क्योंकि यह अब ढेर पर नहीं है (इसे प्रभावी रूप से bar के साथ बदल दिया गया है)।

दूसरा कैसे आप जुड़े हैं से
+0

यह टीसीओ का एक बड़ा स्पष्टीकरण है। क्या आपके पास कोई विशिष्ट संदर्भ है जो एलिक्सीर के कार्यान्वयन की व्याख्या करता है? –

+4

यह काम एरलांग कंपाइलर द्वारा किया जाता है। आप एलिक्सी को एर्लांग असेंबली में संकलित कर सकते हैं यह देखने के लिए कि टीसीओ लागू है (https://gist.github.com/sasa1977/73274c2be733b5321ace)। मैं Erlang के कंपाइलर के स्रोत कोड के अलावा किसी भी संदर्भ से अवगत नहीं हूं :-) – sasajuric

+0

अरे @ sasajuric क्या मुझे यहां कुछ याद आ रही है? "def foo do" और फिर "बार()"? अंतिम कथन "foo()" नहीं होना चाहिए? –

संबंधित मुद्दे