context {gestalt}R Documentation

Run an Action in an Ordered Context

Description

Programming in R typically involves:

  1. Making a context: assigning values to names.

  2. Performing an action: evaluating an expression relative to a context.

let() and run() enable you to treat these procedures as reusable, composable components.

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 envir argument of eval()).

...

Named expressions. An expression looks up values to the left of it, and takes precedence over those in `_data`. Quasiquotation of names and expressions is supported (see ‘Examples’).

`_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


[Package gestalt version 0.2.0 Index]