【发布时间】:2014-06-17 03:41:36
【问题描述】:
由于某种原因,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 中)?
【问题讨论】:
-
似乎 ruby 在左侧之前计算乘法的右侧,因此左侧版本使用tail recursion,因此不必添加到堆栈中。
-
@clcto:这看起来不像是尾调用消除。一方面,乘法是函数中的最后一个操作,而不是递归调用。另一方面,如果你将数字增加到 9500,你仍然会破坏堆栈。
-
@clcto Ruby 最明确地从左到右而不是从右到左评估操作数和方法参数。此外,评估操作数的顺序与某事物是否为尾递归无关。乘法必然发生在函数调用之后(因为在知道两个数字之前,您不能将两个数字相乘),因此无论哪个数字首先被评估,该方法都不是尾递归的。无论哪种方式,标准 Ruby 解释器都不会优化尾递归。
标签: ruby parsing recursion internals