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))"
。
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)))
g <- function(x) deparse(substitute(x))
按预期返回"1:10"
、"x"
和"x + y ^ 2 / z + exp(a * sin(b))"
。
首先,一些背景信息:承诺是一个未求值的参数。一个承诺包括两个部分:1)产生这个延迟计算的代码/表达式(可以通过substitute
或pryr::promise_info
查看该代码),以及2)创建和应该在其中评估该代码/表达式的环境(可以通过pryr::promise_info
查看该环境)。
如果将g()
函数更改为,则问题也更加清晰
g <- function(x) deparse(f(whatever))
你总是会得到 "whatever"。这是因为当 g()
调用 f(whatever)
时,它向 f()
传递了一个 Promise 对象--该对象具有代码 whatever
和 g()
执行环境的环境。然后,在 f()
中的 substitute
查看这个 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
查看的是承诺对象x
(与上述情况中的承诺对象whatever
相反)。 承诺x
在这里具有代码1:10
和环境R_GlobalEnv
。(同样,可以使用g <- function(x) { print(promise_info(x) ; deparse(substitute(x))
进行检查。 因此,substitute(x)
按预期返回1:10
。
我也曾经为此苦恼,以下是我对于清晰解释的理解:
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。创建一个执行环境来执行函数 () - 或 deparse - 并将全局环境作为其父级。在此执行环境中,x = 5。基本上,5 被传递给函数 ()。
然后,在 g 的执行环境之外调用函数 f,即 substitute。创建 f 的执行环境,并将 g 的执行环境作为其父级。传递了一个参数 x。请注意,这个 x 只是一个符号,表示将参数传递给函数。它尚未被评估。
在 f 的执行环境中,此参数未被评估,因为那里只有一个函数 substitute(),根据定义不进行评估。对于任何正常的函数,例如 sqrt(x),需要评估 x。在 f 的执行环境中,找不到这个 x,R 将向上查找到 g 的执行环境。在那里,x 将被找到并且将取出 x 的平方根并返回。
您必须阅读 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 <- 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())创建了执行环境,并将5作为参数传递给它。
deparse(substitute(x))
给出了正确的响应。在这种情况下,g()
调用了substitute(x)
,因此当substitute()
寻找传递给它的表达式时,它总是看到x
。为什么不是这样呢? - Heisenbergdeparse(substitute(x))
之所以有效,是因为你没有第二级的重定向。在f()
和g()
中的x
是不同的。实际上,substitute
是在传递给函数的 promise 对象上工作的。一旦你调用另一个函数,那个 promise 就必须被解析。因此,如果你在同一个函数调用中完成它,就不会有这个问题。 - MrFlicksubstitute
函数是在处理传递给它的 Promise 对象。”你所指的 Promise 对象和函数是什么?(只是澄清) - Heisenbergdeparse(substitute(x))
,符号是x
,表达式槽包含您实际传递给函数的内容,例如1:10
。 - MrFlick