2010-06-29 21 views
5

Başarısız olursa bir ifadeyi yeniden denenecek bir işlev oluşturmak istiyorum. Sonra ben her tekrarlayan çağrı uyarıları bir dizi olsun, yukarıda suppressWarnings() fonksiyonunu kaldırırsanızYinelenen ifadede R uyarı iletisi: Başarısız olursa, yeniden deneyin. Yeniden deneyin.

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")) 

: İşte benim çalışma versiyonu. Yanlış yaptığımı bilen kimse buna sebep olur mu? bunlar yok bir for döngü kullanırsanız uyarıları almak neden

retry({ tmp <- function() { if(rnorm(1) < 0) stop("I'm here") else "success" }; tmp() }) 

cevap

6

ben tam olarak nedenini açıklamak eğer emin değilim, ama sorunu izole ettik ve tamir edebiliriz. Temel sorun özyinelemedir: - özyinelemeli çağrı substitute(.FUN) aradığında, .FUN değerinin ne olduğunu bulmak için bir çağrı yığınının seviyesine çıkacaktır - bir sözün değerlendirmesini yeniden başlatmak zorundadır (gecikmiş yürütme işlev argümanları) bir seviye yukarı.

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()) 

ederim yerine kullanılmasını en aza tavsiye sen esnek kullanabilirsiniz işlevler oluşturmak için:

bir düzeltme kez ikame tıpkı etmektir. Tecrübemde, genellikle ikame işlemini yapan bir fonksiyona sahip olmanın en iyisi, ve tüm işi yapan başka bir şey. Başka bir işlevi çağrıldığında bu işlevi kullanmak mümkün kılar:

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 
+0

.FUN'nuzun yinelemeli uygulamasının sürümünüzde çalışmayacağını düşünürdüm, çünkü .FUN bu noktada zaten değerlendirilmiş olurdu? Bunu test edeceğim ... – Shane

+0

Sanırım haklısın, ama bu arada bunu anladım. Sanırım f benim daha iyi bir örnek çünkü bazen hatalar ve bazen de değil. Beklediğiniz şeyi kontrol etmek için birkaç kez çalıştırın. Denemelerin bittiğinde geri dönmek istediğinden emin değilim ama hala bir hatam var. – hadley

+0

Oh, Görüyorsunuz ki, postanızın alt kısmına bir eşdeğiniz vardı:/ – hadley

3

Emin değilim ... ama:

Burada defalarca çalıştırılabilir bir örnek.

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 
    } 
+0

Teşekkür @nico; Ben çoğunlukla ikaz ile uyarılara neden olduğunu merak ediyordum. Ama sürümünüz mükemmel çalışıyor! – Shane

İlgili konular