6

我有一个相当复杂的情况,我可能最终将一个不存在的变量传递给函数。我很清楚何时会发生这种情况,但修复它会很困难;我对能够可靠地检测到这种情况并在这种情况下执行解决方法感到满意。我可以简单地使用

inherits(try(eval(possibly_missing_variable),silent=TRUE),"try-error")

但如果可能的话,我想测试导致错误的具体情况object 'possibly_missing_variable' not found。(我可以尝试在错误消息中使用 grep 查找“未找到”,但过去我在 r-devel 列表中被警告说,如果 R 以不同的语言运行,那么这将失败,以便翻译版本的出现错误信息。)

我尝试了 的各种组合deparse(substitute(...)),但它们似乎在调用堆栈上运行得不够远。这是我对可重现示例的最佳拍摄:

f <- function(d) {
    ## test here
    cat("'d' exists:",exists("d"),"\n") ## TRUE
    cat("deparse(substitute(d)):",dd <- deparse(substitute(d)),"\n") ## OK
    cat("exists('",dd,"'): ",exists(dd),"\n",sep="")
    eval(d)
}

f2 <- function(ddd) {
    f(ddd)
}

ddd <- 5
f2(junk)

结果是:

'd' exists: TRUE 
deparse(substitute(d)): ddd 
exists('ddd'): TRUE
Error in eval(d) : object 'junk' not found

我想要一个能够正确通知我(在遇到错误之前)评估将失败的测试,因为在环境/封闭环境等堆栈中的任何地方都找不到相关对象。有什么想法......?

更一般地说,有没有办法找出参数的最上游名称("junk"在这种情况下)?如果我能做到这一点,那么exists(farthest_upstream_name)将解决我的问题。

4

2 回答 2

5

也许是这样的(从我对这个问题的第二个答案中窃取)?

f <- function(d) {
    ## test here
    ff <- sys.frames()
    ex <- substitute(d)
    ii <- rev(seq_along(ff))
    for(i in ii) {
        ex <- eval(substitute(substitute(x, env=sys.frames()[[n]]),
                              env = list(x = ex, n=i)))
    }
    if(!exists(deparse(ex))) stop("Substitute real error action here")
    eval(d)
}

f2 <- function(ddd) {
    f(ddd)
}

ddd <- 5
f2(junk)
## Error in f(ddd) (from #10) : Substitute real error action here
于 2013-02-18T21:31:57.637 回答
3

我喜欢 Josh O'Brien 的方法。但是,f按照那里的定义使用,即使传递的名称确实具有活动绑定,如果它是在调用堆栈中的某个函数本地创建的(而不是在全局环境中),也可以触发“不存在”错误条件)。此外,虽然可能与 Ben 的预期用法没有特别相关,但如果参数是表达式,而不仅仅是名称,则会触发错误。

一个简单的解决方法是调整 Josh 的函数以包含一个is.symbol测试:

f <- function(d) {
    ## test here
    ff <- sys.frames()
    ex <- substitute(d)
    ii <- rev(seq_along(ff))
    for(i in ii) {
        ex <- eval(substitute(substitute(x, env=sys.frames()[[n]]),
                              env = list(x = ex, n=i)))
    }
    if(is.symbol(ex) && !exists(deparse(ex))) {
        stop("Substitute real error action here")
    }
    eval(d)
}

所需的检查仍然有效:

f2 <- function(ddd) {
    f(ddd)
}
f2(junk)
## Error in f(ddd) : Substitute real error action here

但是以下两种情况现在通过而不是产生错误:

# case 1: argument to f is local to a calling function
f3 <- function() {
    notjunk <- 999
    f(notjunk)
}
f3()
## [1] 999

# case 2: argument to f is an expression
f2(5+5)
## [1] 10

发生的情况f是,在重复应用 call-substitute-substitute 之后,ex在上面的案例 1 中设置为评估的参数本身,在案例 2 中设置为传递的(尽管仍然未评估)调用。在这两种情况下,exists单独的测试都会失败是因为ex它实际上不是一个名称(又名符号),但如果我们能够解决名称之外的问题,显然不存在不是问题。

于 2013-02-22T09:48:53.577 回答