15

我最近提出了这个问题,幸好有人指出withRestarts()这对我来说似乎非常棒和强大:-) 现在我渴望更详细地了解 R 的错误处理能力。

实际问题

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

对于那些有兴趣的人

两个代码示例

  1. 我目前withRestarts依赖于这篇博文的使用说明
  2. 尝试定义“自定义条件”

我很感激任何关于如何做得更好的评论/建议;-)

示例 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")
4

1 回答 1

15

这篇文章引用了 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 类,因此可以具有线性层次结构——bad并且worse都是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”S3 类扩展为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;我认为这是调用处理程序旨在解决的情况——一旦您调用重新启动,调用条件的整个帧都准备好等待继续。

于 2013-03-15T21:02:05.287 回答