15

私は最近この質問を提起し、ありがたいことにwithRestarts()、私にとって非常に素晴らしく強力なように思われることを指摘されました:-) 今、私はRのエラー処理機能をもう少し詳しく理解したいと思っています.

実際の質問

  1. のおすすめの使い方はsimpleCondition()?これまで使用したことはありませんでしたが、実際には「真」の状態であるカスタム エラーと警告を設計するのに役立つかもしれないと思いました。特定のハンドラーが利用可能な特定の条件のデータベースを構築するために使用できますか?
  2. Rワークスペース全体の特定の状態を「凍結」し、そこに戻って特定の時点で計算を再開する方法はありますか? 私は知っていますが、知る限り、これは検索パス(または)save.image()の「状態」を保存しません。search()searchpaths()

興味のある方へ

2 つのコード例

  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 の条件処理のインスピレーションを参照しています。

simpleCondition1. については、カスタム条件を作成する方法を説明していると思います。

 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>

これらの条件は、tryCatchまたはwithCallingHandlers

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)

条件のクラスに一致する最初の (? tryCatchtryCatchで説明されている意味で) 単一のハンドラーにアクセスするだけです。

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 に答える