我不確定是否可以完全描述原因,但我已經隔離了這個問題並且可以解決它。基本問題是遞歸: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
我以爲在你的版本中遞歸執行.FUN是行不通的,因爲.FUN在那時已經被評估過了?我會測試它...... – Shane 2010-06-30 17:40:49
我認爲你是對的,但在此期間,我明白了。我認爲我的f是一個更好的例子,因爲有時它是錯誤的,有時它不會。運行幾次,檢查它是否符合你的期望。我不確定你什麼時候想要它返回,當你嘗試用完,但仍然有錯誤。 – hadley 2010-06-30 17:42:59
哦,我看到你在你的帖子底部有一個相當於我的f:/ – hadley 2010-06-30 17:43:36