Я не уверен, что могу точно описать причину, но я выделил проблему и могу ее исправить.Основная проблема - рекурсия: 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