高级错误处理

时间:2013-03-12 13:47:50

标签: r error-handling conditional-statements application-restart

我最近提出了this question,幸好有人指出withRestarts()这对我来说非常棒和强大:-)现在我急于更详细地了解R的错误处理能力。< / p>

实际问题

  1. simpleCondition()的推荐用法是什么?从来没有使用它,但我认为它可能有助于设计实际上是“真实”条件的自定义错误和警告。是否可以用于构建特定条件的数据库,以获取特定的处理程序?
  2. 有没有办法“冻结”整个 R工作空间的某个状态并返回到它以在某个点重新开始计算?我知道save.image(),但是AFAIU,这不会存储搜索路径的“状态”(search()searchpaths())。

  3. 对于那些感兴趣的人

    两个代码示例

    1. 我目前使用withRestarts依赖于此blog post
    2. 的插图
    3. 尝试定义“自定义条件”
    4. 我很感激有关如何做得更好的任何意见/建议; - )

      示例1

      require("forecast")
      autoArimaFailsafe <- function(
          x,
          warning=function(w, ...) {
              message("autoArimaFailsafe> warning:")
              message(w)
              invokeRestart("donothing")},
          error=function(e, ...) {
              message("autoArimaFailsafe> error:")
              message(e)
              invokeRestart("abort")}
      ) {
          withRestarts(
              out <- tryCatch(
                 {
                      expr <- expression(auto.arima(x=x))
                      return(eval(expr))
                 },
                 warning=warning,
                 error=error 
              ),
              donothing=function(...) {
                  return(eval(expr))
              },
              abort=function(...) {
                  message("aborting")
                  return(NULL)
              }
          )    
      }
      data(AirPassengers)
      autoArimaFailsafe(x=AirPassengers)
      autoArimaFailsafe(x="a")
      

      示例2

      require("forecast")
      autoArimaFailsafe <- function(
          x,
          warning=function(w, ...) {
              message("autoArimaFailsafe> warning")
              invokeRestart("donothing")},
          error=function(e, ...) {
              message("autoArimaFailsafe> error")
              invokeRestart("abort")},
          condition=function(cond, ...) {
              out <- NULL
              message(cond)
              condmsg     <- conditionMessage(c=cond)
              condclass   <- class(cond)
              if (any(class(cond) == "simpleWarning")) {
                  out <- warning(w=cond)
              } else if (any(class(cond) == "simpleError")) {
                  out <- error(e=cond)
              } else if (any(class(cond) == "simpleCondition")) {
                  if (condmsg == "invalid class: character") {
                      out <- invokeRestart("forcedefault")
                  }
              }
              return(out)
          }
      ) {
          withRestarts(
              out <- tryCatch(
                 {
                      expr <- expression(auto.arima(x=x))
                      if (class(x) == "character") {
                          expr <- signalCondition(
                              simpleCondition("invalid class: character", 
                                  call=as.call(expr))
                          )
                      }
                      return(eval(expr))
                 },
                 condition=condition
              ),
              donothing=function(...) {return(eval(expr))},
              abort=function(...) {
                  message("aborting")
                  return(NULL)
              },
              forcedefault=function(...) {
                  data(AirPassengers)
                  expr <- expression(auto.arima(x=AirPassengers))
                  return(eval(expr))
              } 
          )
      }
      autoArimaFailsafe(x=AirPassengers)
      autoArimaFailsafe(x=NULL)
      autoArimaFailsafe(x="a")
      

1 个答案:

答案 0 :(得分:12)

This帖子引用了R条件处理的灵感。

对于1.,我认为simpleCondition说明了如何构建自定义条件,例如。

 myCondition <-
    function(message, call=NULL, type=c("overflow", "underflow", "zero"))
{
    type <- match.arg(type)             # only allowed types past here
    class <- c(type, "my", "condition")
    structure(list(message = as.character(message), call = call), 
        class = class)
}

是用于制作自定义条件的构造函数

> myCondition("oops")
<overflow: oops>
> myCondition("oops", type="underflow")
<underflow: oops>

这些条件可以在tryCatchwithCallingHandlers

中使用
xx <- tryCatch({
    signalCondition(myCondition("oops", type="underflow"))
}, underflow=function(e) {
    message("underflow: ", conditionMessage(e))
    NA # return value, assigned to xx
})

这些是S3类,因此可以具有线性层次结构 - badworse都是error的子类。

myError <-
    function(message, call=NULL, type=c("bad", "worse"))
{
    type <- match.arg(type)
    class <- c(type, "error", "condition")
    structure(list(message=as.character(message), call=call),
              class=class)
}

还可能会创建一个错误,将'simpleError'S2类扩展为cond <- simpleError("oops"); class(cond) = c("myerr", class(cond)

使用tryCatch我们只能访问单个处理程序,第一个(在tryCatch中描述的意义上)匹配条件类

tryCatch({
    stop(myError("oops", type="worse"))
}, bad = function(e) {
    message("bad error: ", conditionMessage(e))
}, worse = function(e) {
    message("worse error: ", conditionMessage(e))  # here's where we end up
}, error=function(e) {
    message("error: ", conditionMessage(e))
})

使用withCallingHandlers我们有机会点击多个处理程序,只要我们不调用重启

withCallingHandlers({
    stop(myError("oops", type="bad"))
}, bad = function(e) {                             # here...
    message("bad error: ", conditionMessage(e))
}, worse = function(e) {
    message("worse error: ", conditionMessage(e))
}, error=function(e) {                             # ...and here...
    message("error: ", conditionMessage(e))
})                                                 # ...and top-level 'error'

withCallingHandlers({
    x <- 1
    warning(myError("oops", type="bad"))
    "OK"
}, bad = function(e) {                     # here, but continue at the restart
    message("bad warning: ", conditionMessage(e))
    invokeRestart("muffleWarning")
}, worse = function(e) {
    message("worse warning: ", conditionMessage(e))
})

我对你的问题2不太确定;我认为这是调用处理程序旨在解决的情况 - 一旦调用重新启动,调用条件的整个框架将等待继续。