In my two previous post on non-standard evaluation, *Scoping rules and NSE* and *Overscoping and eval*, I explained:

- How R finds the bindings of variables by looking through chains of environments.
- How you can manipulate these environments to evaluate expressions in a non-standard way.
- How you can evaluate expressions where lists or data-frames overscope variables that would otherwise be found in environments.

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: