我不确定我是否可以准确描述原因,但我已经隔离了问题并可以解决它。基本问题是递归:retry(.FUN, max.attempts-1) - 当递归调用调用 substitute(.FUN) 时,它会上升到调用堆栈的一层来确定 .FUN 的值是什么 - 它必须重新开始评估一个承诺(函数参数的延迟执行)升级。
解决方法是只进行一次替换:
retry <- function(.FUN, max.attempts = 3, sleep.seconds = 0.5) {
expr <- substitute(.FUN)
retry_expr(expr, max.attempts, sleep.seconds)
}
retry_expr <- function(expr, max.attempts = 3, sleep.seconds = 0.5) {
x <- try(eval(expr))
if(inherits(x, "try-error") && max.attempts > 0) {
Sys.sleep(sleep.seconds)
return(retry_expr(expr, max.attempts - 1))
}
x
}
f <- function() {
x <- runif(1)
if (x < 0.5) stop("Error!") else x
}
retry(f())
为了创建可以灵活使用的功能,我强烈建议尽量减少使用替代品。根据我的经验,您通常最好使用一个功能来完成替换,而另一个功能来完成所有工作。这使得在从另一个函数调用时可以使用该函数:
g1 <- function(fun) {
message("Function starts")
x <- retry(fun)
message("Function ends")
x
}
g1(f())
# Function starts
# Error in eval(expr, envir, enclos) : object 'fun' not found
# Error in eval(expr, envir, enclos) : object 'fun' not found
# Error in eval(expr, envir, enclos) : object 'fun' not found
# Error in eval(expr, envir, enclos) : object 'fun' not found
# Function ends
g2 <- function(fun) {
message("Function starts")
expr <- substitute(fun)
x <- retry_expr(expr)
message("Function ends")
x
}
g2(f())
# Function starts
# Error in f() : Error!
# Function ends
# [1] 0.8079241