我不确定是否能准确地描述原因,但我已经隔离了问题并能解决它。基本问题是递归:
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