2012-01-04 10 views
5

क्या रुबी में रिकर्सिव फ़ंक्शंस में स्टैक ओवरफ़्लो त्रुटियों के लिए कोई कामकाज है?क्या रिकर्सिव रूटीन में "स्टैक लेवल बहुत गहरी" त्रुटियों के लिए कोई कामकाज है?

def countUpTo(current, final) 
    puts current 
    return nil if current == final 
    countUpTo(current+1, final) 
end 

अगर मैं फोन countUpTo(1, 10000), मैं कोई त्रुटि मिलती है: stack level too deep (SystemStackError)

कहते हैं, उदाहरण के लिए, मैं इस ब्लॉक की है।

यह 8187. में तोड़ने के लिए प्रकट होता है वहाँ कुछ समारोह है कि मैं ढेर के आकार, या अधिकतम ढेर आकार बढ़ाने के लिए एक तरह से अनदेखी करने के लिए रूबी कह कॉल कर सकते हैं है?

+5

ऐसा मत करो। यदि आप जानबूझकर 10,000 बार पुन: उपयोग कर रहे हैं, तो आप इसे बहुत गलत कर रहे हैं और पुनरावृत्ति का दुरुपयोग कर रहे हैं। – meagar

+2

रूबी कार्यान्वयन जरूरी नहीं है कि पूंछ कॉल उन्मूलन करें, इसलिए आप सी स्टैक आकार का उपयोग करने पर भरोसा कर रहे हैं। एक संभावना यह है कि आप अपने कार्य को पुनरावृत्त करने के लिए पुनः लिख सकते हैं। – birryree

+0

सबसे पहले, रूबी के साथ मेरा स्वयं का अनुभव यह है कि यह रिकर्सन के साथ विशेष रूप से अच्छा नहीं है, जिसमें यह इस तरह की त्रुटियों को आसानी से उत्पन्न करता है और यह धीमा है (आप चाहते हैं कि इससे भी कम)। इसके अलावा, इस क्षेत्र में बेहतर प्रदर्शन करने के लिए आपको रूबी को एक निश्चित स्थिर सेट के साथ संकलित करने की आवश्यकता है, लेकिन मुझे यह नहीं मिला कि इससे बहुत मदद मिली। दूसरे शब्दों में, सामान्य रूप से रूबी विधियों जैसे 'times',' upto' आदि का उपयोग करके अपने फ़ंक्शन को अलग-अलग लिखें, जब तक कि आपको पता न हो कि लक्ष्य क्या है, मुझे नहीं लगता कि आप यह दावा कर सकते हैं। मैंने हास्केल में विधियों को लिखा है कि उस समय की कोई समस्या नहीं है और यह एक कठोर है। – iain

उत्तर

2

आप YARV (सी रूबी 1.9 के आधार पर कार्यान्वयन) का उपयोग कर रहे हैं, तो आप पर पूंछ कॉल अनुकूलन चालू करने के लिए रूबी वीएम बता सकते हैं:

RubyVM::InstructionSequence.compile_option = { 
    :tailcall_optimization => true, 
    :trace_instruction => false 
} 

def countUpTo(current, final) 
    puts current 
    return nil if current == final 
    countUpTo(current+1, final) 
end 

countUpTo(1, 10_000) 
+0

जैसा कि मैंने उपरोक्त लिखा है, मैंने पाया कि यह थोड़ा प्रभावशाली है, लेकिन वाईएमएमवी। – iain

+0

compile_option सेट करने के बाद, आप निर्देश अनुक्रम पर 'new' या 'compile' विधियों का उपयोग कर सकते हैं, उदाहरण के लिए:' RubyVM :: InstructionSequence.new ('def meth_name (b, c); d = b + c; puts" # {बी} + # {सी} = # {डी}। अब # {बी + 1} + # {सी} ... "; meth_name (बी + 1, सी) अंत ')। eval'। ऐसा करने का एक और सामान्य तरीका दिखाया गया है [यहां] (https://gist.github.com/rogerleite/5101751)। –

+0

या यदि आप सब कुछ के लिए विकल्प सेट नहीं करना चाहते हैं, तो आप विकल्पों को संकलित/नए में भेज सकते हैं, उदा। 'RubyVM :: InstructionSequence.new ('def meth_name (बी, सी); डी = बी + सी;" # {b} + # {c} = # {d} डालता है। अब # {b + 1} + # कर रहा है {सी} ... "; meth_name (बी + 1, सी) अंत ', शून्य, शून्य, शून्य, tailcall_optimization: सच, trace_instruction: झूठा) .eval'। अधिक देखें के लिए [:: रूबीवीएम :: निर्देश की आवश्यकता] (http://www.ruby-doc.org/core-2.0.0/RubyVM/InstructionSequence.html) देखें। –

2

आप अपने टुकड़ा नहीं पुनर्लेखन कर सकते हैं पुनरावर्ती होने के लिए:

# 'count_up_to' would be a more "Ruby" name ;-) 
def countUpTo(current, final) 
    (current..final).each { |i| puts i } 
end 

मैं सराहना अपने कोड शायद तुम सच में ऐसा करने की कोशिश कर रहे हैं क्या का एक अमूर्त है, लेकिन यह अपने समाधान के रूप में अगर आपको लगता है मदद कर सकता है पुनरावर्ती के बजाय पुनरावृत्त करने के अन्य तरीकों के।

HTH

+0

सामान्य रूप से, असंबद्ध रिकर्सन खराब है। अधिकांश रिकर्सन को पुनरावृत्त करने के लिए फिर से लिखा जा सकता है क्योंकि पावलिंग ने दिखाया है। – nmjohn

+0

यह डाउनवोट के योग्य कैसे था ?! }: - [ – Pavling

+0

@ पैवलिंग: क्योंकि आप यह कहने के लिए वैध कारण दिए बिना "ऐसा नहीं करते" (रिकर्सन न करें) कह रहे हैं। –

2

रूबी 2.0 आप कर सकते हैं में RUBY_THREAD_VM_STACK_SIZE और अन्य पर्यावरण चर का उपयोग करके स्टैक आकार (बाइट्स में) निर्दिष्ट करें।

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