代码之家  ›  专栏  ›  技术社区  ›  andrewH

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

  •  4
  • andrewH  · 技术社区  · 7 年前

    当应用于相同的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 回复  |  直到 7 年前
        1
  •  4
  •   joran    7 年前

    原因是 substitute() 根据你所说的不同,或者更准确地说,是你所说的不同。

    理解将要发生的事情需要非常仔细地分析 代换() ,具体地说:

    通过检查解析树的每个组件进行替换 如下:如果它不是env中的绑定符号,则它是不变的。如果它 是承诺对象,即函数的形式参数或 使用delayedassign()显式创建,它是 承诺取代了符号。如果它是一个普通变量,它的值 被替换,除非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 是函数的形式参数,因此这意味着我们 不同的 记录的行为案例。

    具体地说,现在“承诺的表达槽取代了符号”。如果我们 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 是承诺的对象,并且 代替 替换符号 X 用它所指的那个,即 DF1 . 这就是docs所说的“承诺的表达槽”;这就是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