如何使quote()和Alternative()输出的差异可见?

时间:2019-01-18 16:22:55

标签: r metaprogramming substitution quote

应用于相同的R代码或对象时,引用和替换通常返回不同的对象。怎样才能使这种区别显而易见?

is.identical <- function(X){
  out <- identical(quote(X), substitute(X))
  out
}

> tmc <- function(X){
   out <- list(typ = typeof(X), mod = mode(X), cls = class(X))
   out
 }

> df1 <- data.frame(a = 1, b = 2)

这里报价和替代品的打印输出是相同的。

> quote(df1)
df1
> substitute(df1)
df1

两者的结构相同。

> str(quote(df1))
 symbol df1
> str(substitute(df1))
 symbol df1

并且类型,模式和类都相同。

> tmc(quote(df1))
$typ
[1] "symbol"
$mod
[1] "name"
$cls
[1] "name"

> tmc(substitute(df1))
$typ
[1] "symbol"
$mod
[1] "name"
$cls
[1] "name"

但是,输出不相同

> is.identical(df1)
[1] FALSE

请注意,this question显示了一些输入,这些输入使两个功能显示不同的输出。但是,即使它们看起来相同,输出也不同,并且在大多数通常的测试中它们都是相同的,如上述is.identical()的输出所示。这种看不见的区别是什么?如何使它显现?

在标签上注意:我猜通用LISP引号和R引号相似

1 个答案:

答案 0 :(得分:4)

原因是substitute()的行为因调用位置而不同,或更确切地说,取决于调用的内容。

要了解会发生什么,需要非常仔细地解析substitute()的(细微)文档,尤其是:

  

通过检查解析树的每个组件来进行替换   如下所示:如果它不是env中的绑定符号,则它保持不变。如果它   是一个promise对象,即函数或函数的形式参数   使用delayAssign()显式创建的   许诺替换符号。如果是普通变量,则其值为   被替换,除非env为.GlobalEnv,在这种情况下,符号为   保持不变。

所以实际上有三个选择。

在这种情况下:

> df1 <- data.frame(a = 1, b = 2)
> identical(quote(df1),substitute(df1))
[1] TRUE

df1是一个“普通变量”,但是.GlobalEnv中被调用,因为env参数默认为当前评估环境。因此,在最后一种情况下,符号df1保持不变,因此与quote(df1)的结果相同。

在函数的上下文中:

is.identical <- function(X){
    out <- identical(quote(X), substitute(X))
    out
}

重要的区别在于,现在我们在X而不是df1上调用这些函数。对于大多数R用户来说,这是一个愚蠢的琐碎区别,但是当使用诸如substitute之类的微妙工具时,它变得很重要。 X是函数的形式参数,因此这意味着我们处于所记录行为的不同情况下。

具体地说,它说现在“ promise的表达方式代替符号”。我们可以了解如果debug()函数并在函数环境的上下文中检查对象,这意味着什么:

> debugonce(is.identical)
> is.identical(X = df1)
debugging in: is.identical(X = df1)
debug at #1: {
    out <- identical(quote(X), substitute(X))
    out
}
Browse[2]> 
debug at #2: out <- identical(quote(X), substitute(X))
Browse[2]> str(quote(X))
 symbol X
Browse[2]> str(substitute(X))
 symbol df1
Browse[2]> Q

现在我们可以看到发生的事情恰恰是文档所说的事情(哈!太明显了!;))

X是形式参数或诺言,根据R,它与df1不同。对于大多数编写函数的人来说,它们实际上是相同的,但是内部实现却不同。 X是一个承诺对象,substitute用它“指向”的符号X替换符号df1。这就是文档“承诺的表达方式”的意思;这就是R在函数调用的X = df1部分中看到的内容。

为解决问题,尝试猜测在这种情况下会发生什么:

is.identical <- function(X){
    out <- identical(quote(A), substitute(A))
    out
}

is.identical(X = df1)

(提示:现在A并不是“环境中的绑定符号”。)

最后一个示例更直接地说明了文档中的最终情况,但带有令人困惑的异常:

#Ordinary variable, but in .GlobalEnv
> a <- 2
> substitute(a)
a

#Ordinary variable, but NOT in .GlobalEnv
> e <- new.env()
> e$a <- 2
> substitute(a,env = e)
[1] 2