In my two previous post on non-standard evaluation, Scoping rules and NSE and Overscoping and eval, I explained:
I finished the last post with a model-fitting example, where the lm
function fits data to a formulae, by saying that this particular example had more going on than you might expect. When we write something like
lm(y ~ x, data = df)
it looks as if the lm
function uses over-scoping to search for x
and y
in the df
data frame first, and if that fails, it looks ine the calling scope. This is something we might implement using eval
and parent.frame
(or the more aptly named rlang::caller_env
). This is, in fact, not what is happening. It almost is, yes, but not quite. The lm
function does use overscoping to put df
in front of environments, but it does not look in the calling environment; it looks in the formulas environment.1
x <- rnorm(5); y <- rnorm(5)
lm(y ~ x)
##
## Call:
## lm(formula = y ~ x)
##
## Coefficients:
## (Intercept) x
## -1.1625 -0.5801
We will use this function to contrast an environment from a closure with one we create at the global scope:
closure_formula <- function() {
x <- rnorm(5); y <- rnorm(5)
y ~ x
}
The graph of environments looks like this: