non-standard evaluation, confusion in advanced R book

316 views Asked by At

So in Hadley's advanced R book, there is an example of an issue with using substitute, here is an excerpt of the code:

subset2 <- function(x, condition) {
condition_call <- substitute(condition)
r <- eval(condition_call, x, parent.frame())
x[r, ]
}

scramble <- function(x) x[sample(nrow(x)), ]

subscramble <- function(x, condition) {
 scramble(subset2(x, condition))
}


subscramble(sample_df, a >= 4)
# Error in eval(expr, envir, enclos) : object 'a' not found
traceback()
#> 5: eval(expr, envir, enclos)
#> 4: eval(condition_call, x, parent.frame()) at #3
#> 3: subset2(x, condition) at #1
#> 2: scramble(subset2(x, condition)) at #2
#> 1: subscramble(sample_df, a >= 4)

Can you see what the problem is? condition_call contains the expression condition. So when we evaluate condition_call it also evaluates condition, which has the value a >= 4. However, this can’t be computed because there’s no object called a in the parent environment. But, if a were set in the global environment, even more confusing things can happen:

There are several things that are confusing to me in the above paragraph from the book.

  1. The sentence "condition_call contains the expression condition". The symbol "condition" is used as formal argument in function subset2 and also used in real argument in scramble(subset2(x,condition)). I guess he referred to this real/calling argument "condition", correct?

  2. As a promise, condition in the definiton of subscramble is lazy evaluated? Why it is not evaluated when invoking: scramble(subset2(x,condition))

In other words, how do I know whether a promise is evaluated or not by looking at code? For example, if I understand it correctly, if I change the code to the following:

scramble(subset2(x,(condition))) 

now condition is forced to be evaluated. What are rules here?

  1. When Hadley says "when we evaluate condition_call, it also evaluates condition", what is "it"? Did he mean that "eval" triggered some sort of internal or secondary evaluation that tries to resolve the promise "condition"? Where does this occur? i.e. What is the environment that R tries to use to find out what is the value of "condition"?

  2. So the error "object a not found" is not due to "x" or "parent.frame()" in the invocation below, but rather somewhere else?? I am completely confused.

    r <- eval(condition_call, x, parent.frame())

1

There are 1 answers

0
Pk.yd On

I can't make a comment so I'll post this as an answer. Everything will just be a rehash of :

Non standard evaluation from another function in R

Essentially what happens is in sample_df calling environment the function will be looking for "condition" instead of "a>=4". Since it can't find this it moves up and then finds the condition in the calling environment; the subscramble execution environment (this is because subset2(x, condition) is a promise created in this environment) where it finds a>=4.

Now it needs to find a, but we have already left the sample_df data environment so it searches for it in the global environment leading to strange results if a is defined in the global environment.