Ich bin mir nicht sicher, ob ich die Ursache genau beschreiben kann, aber ich habe das Problem isoliert und kann es beheben. Das grundlegende Problem ist die Rekursion: retry(.FUN, max.attempts-1)
- wenn der rekursive Aufruf substitute(.FUN)
muss es eine Ebene des Aufrufstapels nach oben gehen, um herauszufinden, was der Wert von .FUN
ist - sie muss die Auswertung eines Versprechens (die verzögerte Ausführung von Funktionsargumenten) eine Ebene höher neu starten.
Eine Lösung besteht darin, die Ersetzung nur einmal vorzunehmen:
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())
Um Funktionen zu erstellen, die Sie flexibel einsetzen können, empfehle ich, die Verwendung von substitute auf ein Minimum zu beschränken. Meiner Erfahrung nach ist es in der Regel am besten, eine Funktion zu haben, die die Ersetzung vornimmt, und eine andere, die die ganze Arbeit erledigt. So kann man die Funktion verwenden, wenn sie von einer anderen Funktion aus aufgerufen wird:
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