deparse(substitute())正常返回函数名,但是在for循环中调用函数代码

A. *_*tam 10 r non-standard-evaluation

在一个非常具体的案例中,我对R的行为感到有些惊讶.假设我定义了一个square返回其参数平方的函数,如下所示:

square <- function(x) { return(x^2) }
Run Code Online (Sandbox Code Playgroud)

我想在另一个函数中调用这个函数,我也想在我这样做时显示它的名字.我可以使用deparse(substitute()).但是,请考虑以下示例:

ds1 <- function(x) {
  print(deparse(substitute(x)))
}

ds1(square)
# [1] "square"
Run Code Online (Sandbox Code Playgroud)

这是预期的输出,所以一切都很好.但是,如果我传递包含在列表中的函数并使用for循环处理它,则会发生以下情况:

ds2 <- function(x) {
  for (y in x) {
    print(deparse(substitute(y)))
  }
}

ds2(c(square))
# [1] "function (x) "   "{"               "    return(x^2)" "}"  
Run Code Online (Sandbox Code Playgroud)

任何人都可以向我解释为什么会发生这种情况以及如何防止它发生?

akr*_*ica 10

只要x在函数内部使用它,它就会被评估,因此它"停止成为(未评估的)表达式"并且"开始成为其结果值(已计算的表达式)".为了防止这种情况,您必须捕获x通过substitute你使用它的第一次之前.

结果substitute是一个对象,您可以查询它,就像它是一个列表.所以你可以使用

x <- substitute(x)
Run Code Online (Sandbox Code Playgroud)

然后x[[1]](函数名)x[[2]]和以下(函数的参数)

这样可行:

ds2 <- function(x) {
    x <- substitute(x)
    # you can do `x[[1]]` but you can't use the expression object x in a
    # for loop. So you have to turn it into a list first
    for (y in as.list(x)[-1]) {
        print(deparse(y))
    }
}
ds2(c(square,sum))
## [1] "square"
## [1] "sum"
Run Code Online (Sandbox Code Playgroud)

  • 了不起,谢谢。显然,这方面的技术术语是“承诺对象”。虽然`x` 是一个promise,它的元素(当分配给`y` 时)不再是promise,因此`substitute` 返回一个不同的值。 (2认同)