使用`withCallingHandlers`捕获任意条件 [英] Capture Arbitrary Conditions with `withCallingHandlers`

查看:109
本文介绍了使用`withCallingHandlers`捕获任意条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个函数,该函数将评估代码并存储结果,包括代码中指出的所有可能情况。除了在错误处理表达式中运行我的函数(我们称其为 evalcapt )的情况之外,我的工作情况还不错。

I'm trying to write a function that will evaluate code and store the results, including any possible conditions signaled in the code. I've got this working perfectly fine, except for the situation when my function (let's call it evalcapt) is run within an error handling expression.

问题是 withCallingHandlers 将继续寻找匹配的条件处理程序,如果有人在我的函数之外定义了这样的处理程序,则我的函数将失去控制执行。以下是问题的简化示例:

The problem is that withCallingHandlers will keep looking for matching condition handlers and if someone has defined such a handler outside of my function, my function loses control of execution. Here is simplified example of the problem:

evalcapt <- function(expr) {
  conds <- list()
  withCallingHandlers(
    val <- eval(expr),
    condition=function(e) {
      message("Caught condition of class ", deparse(class(e)))
      conds <<- c(conds, list(e))
  } )
  list(val=val, conditions=conds)
}

myCondition <- simpleCondition("this is a custom condition")
class(myCondition) <- c("custom", class(myCondition))
expr <- expression(signalCondition(myCondition), 25)

tryCatch(evalcapt(expr))          

按预期工作

Caught condition of class c("custom", "simpleCondition", "condition")
$val
[1] 25

$conditions
$conditions[[1]]
<custom: this is a custom condition>

但是:

tryCatch(
  evalcapt(expr),               
  custom=function(e) stop("Hijacked `evalcapt`!")  
)

不起作用:

Caught condition of class c("custom", "simpleCondition", "condition")
Error in value[[3L]](cond) : Hijacked `evalcapt`!



我不知道如何实现的解决方案



我真正需要的是一种在代码中指出条件后立即定义重新启动的方法,坦白地说, withCallingHandlers 似乎正常工作(当我处理程序是最后一个可用的处理程序),但是当我在处理函数中浏览并使用 computeRestarts

A Solution I don't Know How To Implement

What I really need is a way of defining a restart right after the condition is signaled in the code which frankly is the way withCallingHandlers appears to work normally (when my handler is the last available handler), but I don't see the restart established when I browse in my handling function and use computeRestarts.

tryCatch withCallingHandlers ,因为它在找到第一个处理程序后不会继续寻找处理程序。最大的问题是条件后它也不会继续评估代码。如果您看上面的示例,但在 tryCatch 中的 withCallingHandlers 子目录中,则值(25)不之所以返回,是因为在处理完条件后,执行又回到了 tryCatch 框架。

tryCatch does not have the same problem as withCallingHandlers because it does not continue looking for handlers after it finds the first one. The big problem with is it also does not continue to evaluate the code after the condition. If you look at the example that worked above, but sub in tryCatch for withCallingHandlers, the value (25) does not get returned because execution is brought back to the tryCatch frame after the condition is handled.

,我正在寻找 tryCatch withCallingHandlers 之间的混合体,它可以将控制权返回给条件信号器,而且还可以

So basically, I'm looking for a hybrid between tryCatch and withCallingHandlers, one that returns control to the condition signaler, but also stops looking for more handlers after the first one is found.

但是,如何分解(以及到处都是带有信号状态的更复杂的函数):

Okay, but how do you break up (and more complex functions with signaled conditions all over the place):

fun <- function(myCondition) {
  signalCondition(myCondition)
  25
}
expr <- expression(fun())



其他



我在寻找与关联的源代码。Internal(.signalCondition())调用以查看是否可以确定是否设置了幕后重启功能,但是我不知道该做些什么。似乎:

Misc

I looked for the source code associated with the .Internal(.signalCondition()) call to see if I can figure out if there is a behind the scenes restart being set, but I'm out of my depth there. It seems like:

    void R_ReturnOrRestart(SEXP val, SEXP env, Rboolean restart)
    {
        int mask;
        RCNTXT *c;

        mask = CTXT_BROWSER | CTXT_FUNCTION;

        for (c = R_GlobalContext; c; c = c->nextcontext) {
        if (c->callflag & mask && c->cloenv == env)
            findcontext(mask, env, val);
        else if (restart && IS_RESTART_BIT_SET(c->callflag))
            findcontext(CTXT_RESTART, c->cloenv, R_RestartToken);
        else if (c->callflag == CTXT_TOPLEVEL)
            error(_("No function to return from, jumping to top level"));
        }
    }

来自src / main / errors.c正在执行某些操作重新启动调用中的一个,被 do_signalCondition 调用,但是我不知道如何处理它。

from src/main/errors.c is doing some of that restart invocation, and this is called by do_signalCondition, but I don't have a clue how I would go about messing with this.

推荐答案

我想您正在寻找的是在信号发出特殊情况时使用 withRestarts 来自警告

I think what you're looking for is to use withRestarts when your special condition is signaled, like from warning:

    withRestarts({
        .Internal(.signalCondition(cond, message, call))
        .Internal(.dfltWarn(message, call))
    }, muffleWarning = function() NULL)

so

evalcapt <- function(expr) {
  conds <- list()
  withCallingHandlers(
    val <- eval(expr),
    custom=function(e) {
      message("Caught condition of class ", deparse(class(e)))
      conds <<- c(conds, list(e))
      invokeRestart("muffleCustom")
  } )
  list(val=val, conditions=conds)
}

expr <- expression(withRestarts({
    signalCondition(myCondition)
}, muffleCustom=function() NULL), 25)

导致

> tryCatch(evalcapt(expr))   
Caught condition of class c("custom", "simpleCondition", "condition")
$val
[1] 25

$conditions
$conditions[[1]]
<custom: this is a custom condition>


> tryCatch(
+   evalcapt(expr),               
+   custom=function(e) stop("Hijacked `evalcapt`!")  
+ )
Caught condition of class c("custom", "simpleCondition", "condition")
$val
[1] 25

$conditions
$conditions[[1]]
<custom: this is a custom condition>

这篇关于使用`withCallingHandlers`捕获任意条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆