创建一个简单的递归函数,如下所示。
var result = await collection.Find(query)
.Project<Hamster>(Builders<Hamster>.Projection.Exclude(hamster => hamster.FirstName).
Exclude(hamster => hamster.LastName))
.ToListAsync();
当n设置为1e4时,它显示错误power <- function(x, n) {
if(n >= 1) x * power(x, n-1)
else 1
}
。正如错误消息所示,我更新了option参数,在这种情况下,遇到infinite recursion
错误。
stack overflow
Scala支持尾递归,因此可以处理## error to run power 10000 times with defalult option
options()$expressions
#[1] 5000
power(2, 1e3)
#[1] 1.071509e+301
power(2, 1e4)
#Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
#Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?
## expressions parameter updated and results in stack overflow
options(expressions = 100000)
power(2, 1e4)
#Error: protect(): protection stack overflow
错误,并且我稍微更改了函数。
stack overflow
然而,似乎情况会变得更糟,因为当n设置为1e3时,更新的函数会抛出## tail recursion supported in Scala
power.rec <- function(x, n, t = 1) {
if(n < 1) t
else power.rec(x, n-1, x*t)
}
错误。当选项参数增加时处理,但当n变为1e4时遇到infinite recursion
错误。
stack overflow
现在我的问题是
如何在没有错误的情况下运行此类功能?
提前致谢。
答案 0 :(得分:5)
尾部呼叫优化未在R中实现,因为R提供对完整呼叫堆栈的访问。来自 Luke Tierney :
关于问题:尾部调用优化不能在R中应用,至少不能以简单的方式应用,因为R的语义通过sys.xyz函数和parent.frame等提供对调用栈的访问。有可能进行一些语义更改,例如只保证对直接调用者的访问,但除非/直到函数调用机制的性能得到改进,否则没有多少意义。
评论有些陈旧(2011),我希望compiler
包可以解决这类问题,但我无法让它发挥作用。所以你要把你的功能变成一个循环:
power.rec2 <- function(x, n, t = 1) {
while(n > 0) {
t <- x * t
n <- n - 1
}
t
}
identical(power.rec(2, 10), power.rec2(2, 10))
# [1] TRUE
identical(power.rec(2, 1e2), power.rec2(2, 1e2))
# [1] TRUE
power.rec2(2, 1e3)
# [1] 1.071509e+301
power.rec2(2, 1e6)
# [1] Inf
注意尾递归优化正是这样做:将递归转换为循环。不幸的是,您只能手动执行此操作。