Рубин левый против правой рекурсии

По какой-то причине Ruby, похоже, работает лучше, когда сталкивается с левой рекурсией. Например:

def left_recursive_factorial(number)
  return 1 if number.zero?
  left_recursive_factorial(number.pred) * number
end

def right_recursive_factorial(number)
  return 1 if number.zero?
  number * right_recursive_factorial(number.pred)
end

Когда я вызываю эти методы со значением более 9000 (😉), я получаю разные результаты:

left_recursive_factorial(9001)
  # => factorial of 9001

right_recursive_factorial(9001)
  # => SystemStackError: stack level too deep
  #    from (pry):6:in `right_recursive_factorial'

Я не мог найти объяснения этого поведения.

Единственное, что, по-видимому, было связано с парсерами LL(), имеющими проблемы с левой рекурсией, и, я думаю, вы можете перевернуть его, но я не сильно его вникнул.

Может ли кто-нибудь объяснить в деталях, что заставляет левые и правые рекурсии работать по-разному (как правило, и в Ruby) и если у вас есть возможность выбрать тот или другой, почему вы его выбрали (и почему это было выбрано в Ruby)?

Ответ 1

Хорошо, я не хакер YARV любого типа, но вот разница, насколько я понимаю. Когда вы вызываете метод, отправитель толкает аргументы метода в стек, тогда вызываемый метод выдает свои аргументы и нажимает на его возвращаемое значение. Сначала с помощью рекурсивного вызова аргумент number еще не был помещен в стек, поэтому стек каждого вызова занимает немного меньше места. Вот почему вы можете получить еще несколько итераций из этой версии, но не намного больше - вы смотрите на снижение процента использования стека на несколько процентов.