Есть ли обходной путь для ошибок "слишком большой уровень стека" в рекурсивных подпрограммах? - PullRequest
5 голосов
/ 04 января 2012

Есть ли обходной путь для ошибок переполнения стека в рекурсивных функциях в Ruby?

Скажем, например, у меня есть этот блок:

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. Есть ли какая-то функция, которую я могу вызвать, говоря Ruby, игнорировать размер стеков или способ увеличить максимальный размер стека?

Ответы [ 3 ]

2 голосов
/ 05 января 2012

Если вы используете YARV (реализация Ruby 1.9 на основе C), вы можете указать виртуальной машине Ruby включить оптимизацию хвостового вызова:

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)
2 голосов
/ 05 сентября 2013

В Ruby 2.0 вы можете указать размер стека (в байтах), используя RUBY_THREAD_VM_STACK_SIZE и другие переменные среды.

2 голосов
/ 05 января 2012

Вы можете переписать свой фрагмент, чтобы он не был рекурсивным:

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

Я ценю, что ваш код, вероятно, является абстракцией того, что вы действительно пытаетесь сделать, но это может помочь сформировать ваше решение, если вы подумаете о других способах итерации, а не рекурсивно.

НТН

...