deparse(substitute())通常返回函数名,但在for循环内部调用时返回函数代码

deparse(substitute())通常返回函数名,但在for循环内部调用时返回函数代码,r,non-standard-evaluation,R,Non Standard Evaluation,我对R在一个非常特殊的案例中的行为感到有点惊讶。假设我定义了一个函数square,它返回其参数的平方,如下所示: square <- function(x) { return(x^2) } 这是预期的输出,因此一切正常。但是,如果我传递包装在列表中的函数并使用for循环处理它,则会发生以下情况: ds2 <- function(x) { for (y in x) { print(deparse(substitute(y))) } } ds2(c(square))

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

square <- function(x) { return(x^2) }
这是预期的输出,因此一切正常。但是,如果我传递包装在列表中的函数并使用for循环处理它,则会发生以下情况:

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

ds2(c(square))
# [1] "function (x) "   "{"               "    return(x^2)" "}"  

ds2只要在函数中使用
x
,它就会被计算,因此它“不再是(未计算的)表达式”并且“开始成为其结果值(计算的表达式)”。为了防止出现这种情况,您必须在第一次使用
x
之前通过
substitute
捕获它

substitute
的结果是一个可以像查询列表一样进行查询的对象。所以你可以用

x <- substitute(x)

太棒了,谢谢。显然,这方面的技术术语是“承诺对象”。虽然
x
是一个承诺,但它的元素(当分配给
y
时)不再是承诺,因此
substitute
返回一个不同的值。奇怪的是,出于我的目的(捕获变量名并在tidyverse中进行一些计算后将其作为标题),deparse是不必要的。替代品(deparse(var))和仅仅替代品(var)之间有什么区别?还有一个额外的问题:对于tidyverse的新NSE,这仍然是最佳实践吗?@JoeTheShmoe
substitute()
返回调用对象,并
deparse()
将调用对象转换为字符串。如果您将
substitute()
的结果提供给标题生成函数,它可能只调用
deparse()
本身,但我真的不知道。在tidyverse中,您很少需要
substitute()
,有关用户提供的对列标题等作出反应的所有方法,请参见小插曲。是的,我通读了那个小插曲,这正是我来到这里的原因。我找不到一个直接的地方,他们谈论将输入作为一个字符处理。我想旧的小插曲中可能有一些奇怪的enquo()和sym()的组合,但我再也看不到了,但也许我只是在某些地方错过了它
x <- substitute(x)
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"