context {gestalt} | R Documentation |
Run an Action in an Ordered Context
Description
Programming in R typically involves:
Making a context: assigning values to names.
Performing an action: evaluating an expression relative to a context.
let()
and run()
enable you to treat these procedures as reusable,
composable components.
-
let()
makes a context: it lazily binds a sequence of ordered named expressions to a child of a given environment (by default, the current one).For instance, in an environment
env
wherez
is in scope,let(env, x = 1, y = x + 2, z = x * y * z)
is equivalent to calling
local({ x <- 1 y <- x + 2 z <- x * y * z environment() })
except
let()
binds the named expressions lazily (as promises) and comprehends tidyverse quasiquotation. -
run()
performs an action: it evaluates an expression relative to an environment (by default, the current one) and, optionally, a sequence of lazily evaluated ordered named expressions.For instance, in an environment
env
wherex
is in scope,run(env, x + y + z, y = x + 2, z = x * y * z)
is equivalent to calling
local({ y <- x + 2 z <- x * y * z x + y + z })
except
run()
, likelet()
, bindsy
andz
lazily and comprehends quasiquotation.
Usage
let(`_data` = parent.frame(), ...)
run(`_data` = parent.frame(), `_expr`, ...)
Arguments
_data |
Context of named values, namely an environment, list or data
frame; if a list or data frame, it is interpreted as an environment (like
the |
... |
Named expressions. An expression looks up values to the left of
it, and takes precedence over those in |
`_expr` |
Expression to evaluate (“run”). Quasiquotation is supported. |
Value
run()
returns the evaluation of `_expr`
in the combined
environment of `_data`
and ...
.
let()
returns an environment where the bindings in ...
are in scope, as
promises, as if they were assigned from left to right in
a child of the environment defined by `_data`
.
Composing Contexts
Contexts, as made by let()
, have an advantage over ordinary local
assignments because contexts are both lazy and composable. Like
assignments, the order of named expressions in a context is significant.
For example, you can string together contexts to make larger ones:
foo <- let(a = ., b = a + 2) %>>>% let(c = a + b) %>>>% run(a + b + c) foo(1) #> [1] 8
Earlier bindings can be overriden by later ones:
bar <- foo[1:2] %>>>% # Collect the contexts of 'foo()' let(c = c - 1) %>>>% # Override 'c' run(a + b + c) bar(1) #> [1] 7
Bindings are promises; they are only evaluated on demand:
run(let(x = a_big_expense(), y = "avoid a big expense"), y) #> [1] "avoid a big expense"
Remark
“Contexts” as described here should not be confused with “contexts” in R's internal mechanism.
See Also
with()
is like run()
, but more limited because it doesn't
support quasiquotation or provide a means to override local bindings.
Examples
# Miles-per-gallon of big cars
mtcars$mpg[mtcars$cyl == 8 & mtcars$disp > 350]
run(mtcars, mpg[cyl == 8 & disp > 350])
run(mtcars, mpg[big_cars], big_cars = cyl == 8 & disp > 350)
# 'let()' makes a reusable local context for big cars
cars <- let(mtcars, big = cyl == 8 & disp > 350)
eval(quote(mpg[big]), cars) # Quoting restricts name lookup to 'cars'
run(cars, mpg[big]) # The same, but shorter and more transparent
run(cars, wt[big])
mtcars$wt[mtcars$cyl == 8 & mtcars$disp > 350]
# Precedence of names is from right to left ("bottom-up"):
a <- 1000
run(`_expr` = a + b, a = 1, b = a + 2) # 4: all references are local
run(list(a = 1), a + b, b = a + 2) # 4: 'b' references local 'a'
run(let(a = 1, b = a + 2), a + b) # 4: 'b' references local 'a'
run(let(a = 1, b = a + 2), a + b, a = 0) # 3: latter 'a' takes precedence
run(list(a = 1, b = a + 2), a + b) # 1003: 'b' references global 'a'
# Bound expressions are lazily evaluated: no error unless 'x' is referenced
run(`_expr` = "S'all good, man.", x = stop("!"))
run(let(x = stop("!")), "S'all good, man.")
let(x = stop("!")) # Environment binding 'x'
try(let(x = stop("!"))$x) # Error: !
# Quasiquotation is supported
a <- 1
run(let(a = 2), a + !!a) #> [1] 3
run(let(a = 1 + !!a, b = a), c(a, b)) #> [1] 2 2