5 Stimmen

R-Warnmeldung bei rekursivem Ausdruck: Wenn Sie scheitern, versuchen Sie es noch einmal

Ich möchte eine Funktion erstellen, die einen Ausdruck erneut versucht, wenn er fehlschlägt. Hier ist meine Arbeitsversion:

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

Wenn ich die suppressWarnings() Funktion oben, dann erhalte ich eine Reihe von Warnungen bei jedem rekursiven Aufruf. Weiß jemand, was ich falsch mache, was das verursachen würde?

Hier ist ein Beispiel, das wiederholt ausgeführt werden kann:

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

8voto

hadley Punkte 97925

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

4voto

nico Punkte 49590

Ich bin mir nicht sicher, warum Sie die Warnungen erhalten... aber wenn Sie eine for Schleife verschwinden sie.

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
  }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X