Я хочу создать функцию, которая повторит выражение, если это перестанет работать. Вот моя рабочая версия:
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() })
Я не уверен, могу ли я точно описать причину, но я изолировал проблему и могу ее исправить. Основная проблема заключается в рекурсии: retry (.FUN, max.attempts-1)
- когда рекурсивный вызов вызывает replace (.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
Не уверен, почему вы получаете предупреждения ... но если использовать для цикла
, они исчезнут.
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
}