Nie jestem pewien, czy potrafię dokładnie opisać przyczynę, ale wyizolowałem problem i mogę to naprawić. Podstawowym problemem jest rekurencja: retry(.FUN, max.attempts-1)
- kiedy wywołanie rekursywne wywoła substitute(.FUN)
, wzrośnie do poziomu stosu wywołań, aby dowiedzieć się, jaka jest wartość .FUN
- musi ponownie uruchomić ocenę obietnicy (opóźnione wykonanie argumentów funkcji) wyższy poziom.
jest poprawka po prostu zrobić podstawienie jednorazowo:
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())
Aby utworzyć funkcje, które można wykorzystać elastycznie, bardzo polecam minimalizując użycie zamiennika. Z mojego doświadczenia wynika, że najlepiej jest mieć jedną funkcję, która zastępuje, i inną, która wykonuje całą pracę. Dzięki temu można korzystać z tej funkcji po wywołaniu z innej funkcji:
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
Myślałem, że rekursywne wykonanie .FUN w Twojej wersji nie będzie działać, ponieważ .FUN zostałaby już oceniona w tym punkcie? Sprawdzę to ... – Shane
Myślę, że masz rację, ale w międzyczasie doszedłem do tego. Myślę, że moje f jest lepszym przykładem, ponieważ czasami to błędy, a czasem nie. Uruchom go kilka razy, aby sprawdzić, czy spełnia on Twoje oczekiwania. Nie jestem pewien, co chciałeś, aby powrócił, gdy skończy Ci się próba, ale nadal występuje błąd. – hadley
O, widzę, że masz odpowiednik mojego f na dole twojego posta:/ – hadley