Tidy evaluation works by rescoping a set of symbols (column names of a data frame for example) to custom bindings. While doing this, it is important to keep the original environment of captured expressions in scope. The gist of tidy evaluation is to create a dynamic scope containing custom bindings that should have precedence when expressions are evaluated, and chain this scope (set of linked environments) to the lexical enclosure of formulas under evaluation. During tidy evaluation, formulas are transformed into formula-promises and will self-evaluate their RHS as soon as they are called. The main trick of tidyeval is to consistently rechain the dynamic scope to the lexical enclosure of each tidy quote under evaluation.
as_overscope(quo, data = NULL)new_overscope(bottom, top = NULL, enclosure = base_env())
overscope_eval_next(overscope, quo, env = base_env())
overscope_clean(overscope)
A quosure.
Additional data to put in scope.
This is the environment (or the bottom of a set of
environments) containing definitions for overscoped symbols. The
bottom environment typically contains pronouns (like .data
)
while its direct parents contain the overscoping bindings. The
last one of these parents is the top
.
The top environment of the overscope. During tidy evaluation, this environment is chained and rechained to lexical enclosures of self-evaluating formulas (or quosures). This is the mechanism that ensures hygienic scoping: the bindings in the overscope have precedence, but the bindings in the dynamic environment where the tidy quotes were created in the first place are in scope as well.
The default enclosure. After a quosure is done self-evaluating, the overscope is rechained to the default enclosure.
A valid overscope containing bindings for ~
,
.top_env
and _F
and whose parents contain overscoped bindings
for tidy evaluation.
The lexical enclosure in case quo
is not a validly
scoped quosure. This is the base environment by
default.
An overscope environment.
A valid overscope: a child environment of bottom
containing the definitions enabling tidy evaluation
(self-evaluating quosures, formula-unguarding, ...).
These functions are useful for embedding the tidy evaluation
framework in your own DSLs with your own evaluating function. They
let you create a custom dynamic scope. That is, a set of chained
environments whose bottom serves as evaluation environment and
whose top is rechained to the current lexical enclosure. But most
of the time, you can just use eval_tidy_()
as it will take
care of installing the tidyeval components in your custom dynamic
scope.
as_overscope()
is the function that powers eval_tidy()
. It
could be useful if you cannot use eval_tidy()
for some reason,
but serves mostly as an example of how to build a dynamic scope
for tidy evaluation. In this case, it creates pronouns .data
and .env
and buries all dynamic bindings from the supplied
data
in new environments.
new_overscope()
is called by as_overscope()
and
eval_tidy_()
. It installs the definitions for making
formulas self-evaluate and for formula-guards. It also installs
the pronoun .top_env
that helps keeping track of the boundary
of the dynamic scope. If you evaluate a tidy quote with
eval_tidy_()
, you don't need to use this.
eval_tidy_()
is useful when you have several quosures to
evaluate in a same dynamic scope. That's a simple wrapper around
eval_bare()
that updates the .env
pronoun and rechains the
dynamic scope to the new formula enclosure to evaluate.
Once an expression has been evaluated in the tidy environment,
it's a good idea to clean up the definitions that make
self-evaluation of formulas possible overscope_clean()
.
Otherwise your users may face unexpected results in specific
corner cases (e.g. when the evaluation environment is leaked, see
examples). Note that this function is automatically called by
eval_tidy_()
.
# NOT RUN {
# Evaluating in a tidy evaluation environment enables all tidy
# features:
expr <- quote(list(.data$cyl, ~letters))
f <- as_quosure(expr)
overscope <- as_overscope(f, data = mtcars)
overscope_eval_next(overscope, f)
# However you need to cleanup the environment after evaluation.
# Otherwise the leftover definitions for self-evaluation of
# formulas might cause unexpected results:
fn <- overscope_eval_next(overscope, ~function() ~letters)
fn()
overscope_clean(overscope)
fn()
# }
Run the code above in your browser using DataLab