代码之家  ›  专栏  ›  技术社区  ›  Shane

关于递归表达式的警告消息:如果失败,请重试

  •  5
  • Shane  · 技术社区  · 16 年前

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

    如果我移除 suppressWarnings() 函数,则每次递归调用都会得到一组警告。有人知道我做错了什么会导致那样吗?

    下面是一个可以重复运行的示例:

    retry({ tmp <- function() { if(rnorm(1) < 0) stop("I'm here") else "success" }; tmp() })
    
    2 回复  |  直到 16 年前
        1
  •  8
  •   Collin    16 年前

    我不确定是否能准确地描述原因,但我已经隔离了问题并能解决它。基本问题是递归: 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
    
        2
  •  4
  •   nico    16 年前

    不知道为什么你会收到警告。。。但如果你用 for

    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
      }