Hadley先进R书中的非标准评估

时间:2014-08-16 03:53:40

标签: r evaluation substitution

在Hadley的Advanced R book中,有一段代码我无法理解输出。

f <- function(x) substitute(x)
g <- function(x) deparse(f(x))
g(1:10)
g(x)
g(x + y ^ 2 / z + exp(a * sin(b)))

为什么他们都返回"x"?特别是当

g <- function(x) deparse(substitute(x))

按预期返回"1:10""x""x + y ^ 2 / z + exp(a * sin(b))"

2 个答案:

答案 0 :(得分:12)

首先,一些背景信息:承诺是一个未经评估的论点。承诺包含两部分:1)引起此延迟计算的代码/表达式(此代码可由substitutepryr::promise_info查看),以及2)此代码/表达式的环境已创建并应进行评估(此环境可由pryr::promise_info查看)。

如果您将g()功能更改为

,问题也会更加清晰
g <- function(x) deparse(f(whatever))

你永远得到&#34;无论如何&#34;。这是因为当g()调用f(whatever)时,它会将promise对象传递给f() - 此对象的代码为whatever,环境为g()&# 39; s执行环境。然后,substitute中的f()查看此promise对象并返回该promise的代码/表达式,在这种情况下为whatever

可以通过运行以下代码来确认promise对象的代码和环境:

library(pryr) # need to install it
f <- function(x) {
  print(promise_info(x))
  substitute(x)
}

g <- function(x) {
  print(environment())
  f(whatever)
}
g(1:10)

最重要的是,您将获得传递给f(whatever)的任何内容。这就是为什么分离这些功能不是一个好主意。一个解决方法是使用

g <- function(...) deparse(f(...))

这样,参数就会传递到f(),而不会在g()中重命名。

另一方面,g <- function(x) deparse(substitute(x)); g(1:10)生成1:10,因为在这种情况下,substitute正在查看promise对象x(与promise对象{{1在上面的例子中)。承诺whatever此处包含代码x和环境1:10。 (同样,可以使用R_GlobalEnv进行检查。g <- function(x) { print(promise_info(x) ; deparse(substitute(x))按预期返回substitute(x)

答案 1 :(得分:0)

我也很挣扎,这是我的明确解释:

f <- function(x) substitute(x)

g <- function(x) deparse(f(x))

g(5)给出“x”。的为什么吗

首先,deparse没有什么区别

f <- function(x) substitute(x)

g <- function(x) (f(x))

g(5)传递x

当我们做g(5)时会发生什么?

首先使用参数x = 5调用g。创建一个exec环境来执行function() - 或deparse - 作为全局环境的父级。在此执行环境中,x = 5.基本上5传递给函数()

然后在g的exec环境中调用函数f,substitute。使用g的exec作为父项创建f的exec环境。传递参数,x。请注意,此x只是一个符号,表示将参数传递给函数。尚未评估。

在f的exec环境中,不评估此参数,因为其中唯一的函数是substitute(),根据定义,它不会计算。对于任何正常函数,例如sqrt(x),需要评估x。在f的exec环境中,找不到这个x,并且R看起来一直到g的exec环境。将找到x并且将获取并返回x的sqrt。

你必须阅读Hackley的书中的“环境”一章才能理解这一点。

例如,运行以下命令以查看传递的参数以及环境:

## g <- function(x)(f(whatever))
f <- function(x) {
print("----------")
print("starting f, substitute")
print("promise info:") 
print(promise_info(x))
print("current env:")
print(environment()) 
print("function was called in env:")
print(parent.frame())
print("now do subst") 

substitute(x)
}

g <- function(x) {
print("--------")
print("##g <- function(x)(f(x))")
print("-----")
print("starting g ")
print("promise info:")
## A promises comprises of two parts: 1) the code / expression that gives rise to this delayed computation and
## 2) the environment where this code / expression is created and should be evaluated in.
print(promise_info(x))  
print("current env:")
print(environment())
print("function was called in env:")
print(parent.frame())
print("now do f(x)")
f(x)
}

当调用g时,传递5作为参数 当调用f时,x作为参数传递(并且这个x永远不会被substitute()评估,它被称为“promise”,只有在需要时才会被评估)

现在,考虑一下 h&lt; - function(y)deparse(substitute(y))

运行:

h <- function(y) {
print("----------")
print("## h <- function(y) deparse(substitute(y))")
print("-----")
print("starting h")
print("promise info:") 
print(promise_info(y))
print("current env:")
print(environment()) 
print("function was called in env:")
print(parent.frame())
deparse(substitute(y))
}

只有一个阶段,为deparse(substitute())创建一个exec环境,并将5作为参数传递给它。