我想创建一个函数,如果失败,将重试表达式。这是我的工作版本:
retry <- function(.FUN, max.attempts=3, sleep.seconds=1) {
x <- NULL
if(max.attempts > 0) {
f <- substitute(.FUN)
x <- try(eval(f))
if(class(x) == "try-error") {
Sys.sleep(sleep.seconds)
return(suppressWarnings(retry(.FUN, max.attempts-1)))
}
}
x
}
retry(stop("I'm here"))
如果我删除上面的suppressWarnings()
函数,那么每次递归调用都会收到一组警告。有谁知道我做错了会导致什么?
以下是可以重复运行的示例:
retry({ tmp <- function() { if(rnorm(1) < 0) stop("I'm here") else "success" }; tmp() })
答案 0 :(得分:7)
我不确定我是否可以准确描述原因,但我已经解决了问题并且可以解决它。递归的基本问题是:retry(.FUN, max.attempts-1)
- 当递归调用调用substitute(.FUN)
时,它会上升到调用堆栈的某个级别,以确定.FUN
的值是什么 - 它必须重新开始对promise的评估(函数参数的延迟执行)升级。
修复就是只进行一次替换:
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
答案 1 :(得分:4)
不确定为什么会收到警告...但是如果使用for
循环则会消失。
retry <- function(.FUN, max.attempts=3, sleep.seconds=1)
{
x <- NULL
for (i in 1:max.attempts)
{
f <- substitute(.FUN)
x <- try(eval(f))
if (class(x) == "try-error")
{
Sys.sleep(sleep.seconds)
}
else
{
return (x)
}
}
x
}