问题
In Hadley's Advanced R book, there is a piece of code that I cannot understand the output.
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)))
Why do they all return "x"
? Especially when
g <- function(x) deparse(substitute(x))
returns the "1:10"
, "x"
, and "x + y ^ 2 / z + exp(a * sin(b))"
as expected.
回答1:
First, some background information: A promise is an unevaluated argument. A promises comprises of two parts: 1) the code / expression that gives rise to this delayed computation (this code can be viewed by substitute
or pryr::promise_info
), and 2) the environment where this code / expression is created and should be evaluated in (this environment can be viewed by pryr::promise_info
).
The question is also clearer if you changed the g()
function to
g <- function(x) deparse(f(whatever))
you would always get "whatever". This is because when g()
calls f(whatever)
, it passes a promise object to f()
--this object has the code whatever
and the environment of g()
's execution environment. Then, the substitute
within f()
looks at this promise object and returns the code / expression of that promise, which is whatever
in this case.
The code and the environment of the promise object can be confirmed by running the following code:
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)
The bottom line is you'll get back whatever you pass to f(whatever)
. That's why it's not a good idea to separate these functions. One work around would be to use
g <- function(...) deparse(f(...))
This way the parameter is passed through to f()
and not renamed in g()
.
On the other hand, g <- function(x) deparse(substitute(x)); g(1:10)
produces 1:10
because, in this case, substitute
is looking at promise object x
(in contrasts to the promise object whatever
in the above case). Promise x
here has the code 1:10
and the environment R_GlobalEnv
. (Again, this can be checked using g <- function(x) { print(promise_info(x) ; deparse(substitute(x))
. So substitute(x)
returns 1:10
as expected.
回答2:
I also struggled with this, here is my take on a clear explanation:
f <- function(x) substitute(x)
g <- function(x) deparse(f(x))
g(5) gives “x”. Why?
First of all the deparse does not make a difference
f <- function(x) substitute(x)
g <- function(x) (f(x))
g(5) delivers x
What happens when we do g(5)?
First of all g is called with argument x = 5. An exec environment is created to execute the function () - or deparse - with as parent the global environment. In this execution environment x = 5. Basically 5 is passed on to the function ()
Then function f, substitute, is called out of the exec environment of g. An exec environment for f is created with as parent the exec of g. An argument is passed , x. Note that this x is just a symbol to indicate that an argument is passed to a function. It is not yet evaluated.
In the exec environment of f, this argument is not evaluated because the only function there is substitute() which by definition does not evaluate. With any normal function, eg sqrt(x), x would need to be evaluated. In the exec environment of f, this x would not be found and R would look one level up to the exec environment of g. There x would be found and the sqrt of x would be taken and returned.
You have to read the chapter “environments” in Hackley’s book in order to understand this.
Eg run following to see what arguments are passed on and what the environments are:
## 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)
}
When g is called, 5 is passed as argument When f is called x is passed as argument (and this x is never evaluated by substitute(), it is called a "promise" and will only be evaluated if and when needed)
Now, consider h <- function(y) deparse(substitute(y))
Run :
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))
}
There is only one stage, an exec environment is created for deparse(substitute()) and 5 is passed on to it as argument.
来源:https://stackoverflow.com/questions/25336780/non-standard-evaluation-in-hadleys-advanced-r-book