R: Quotation

quotation {rlang} | R Documentation

## Quotation

### Description

Quotation is a mechanism by which an expression supplied as argument is captured by a function. Instead of seeing the value of the argument, the function sees the recipe (the R code) to make that value. This is possible because R expressions are representable as regular objects in R:

- Calls represent the action of calling a function to compute a new value. Evaluating a call causes that value to be computed. Calls typically involve symbols to reference R objects.

- Symbols represent the name that is given to an object in a particular context (an environment).

We call objects containing calls and symbols expressions. There are two ways to create R expressions. First you can build calls and symbols from parts and pieces (see `sym()`, `syms()` and `call2()`). The other way is by quotation or quasiquotation, i.e. by intercepting an expression instead of evaluating it.

### Usage

    expr(expr)

    enexpr(arg)

    exprs(..., .named = FALSE, .ignore_empty = c("trailing", "none",
      "all"), .unquote_names = TRUE)

    enexprs(..., .named = FALSE, .ignore_empty = c("trailing", "none",
      "all"), .unquote_names = TRUE, .homonyms = c("keep", "first", "last",
      "error"), .check_assign = FALSE)

    ensym(arg)

    ensyms(..., .named = FALSE, .ignore_empty = c("trailing", "none",
      "all"), .unquote_names = TRUE, .homonyms = c("keep", "first", "last",
      "error"), .check_assign = FALSE)

    quo(expr)

    enquo(arg)

    quos(..., .named = FALSE, .ignore_empty = c("trailing", "none", "all"),
      .unquote_names = TRUE)

    enquos(..., .named = FALSE, .ignore_empty = c("trailing", "none",
      "all"), .unquote_names = TRUE, .homonyms = c("keep", "first", "last",
      "error"), .check_assign = FALSE)

### Arguments

`expr` | An expression.
`arg` | A symbol representing an argument. The expression supplied to that argument will be captured instead of being evaluated.
`...` | For `enexprs()`, `ensyms()` and `enquos()`, names of arguments to capture without evaluation (including `...`). For `exprs()` and `quos()`, the expressions to capture unevaluated (including expressions contained in `...`).
`.named` | Whether to ensure all dots are named. Unnamed elements are processed with `quo_name()` to build a default name. See also `quos_auto_name()`.
`.ignore_empty` | Whether to ignore empty arguments. Can be one of `"trailing"`, `"none"`, `"all"`. If `"trailing"`, only the last argument is ignored if it is empty. Note that `"trailing"` applies only to arguments passed in `...`, not to named arguments. On the other hand, `"all"` also applies to named arguments.
`.unquote_names` | Whether to treat `:=` as `=`. Unlike `=`, the `:=` syntax supports `!!` unquoting on the LHS.
`.homonyms` | How to treat arguments with the same name. The default, `"keep"`, preserves these arguments. Set `.homonyms` to `"first"` to only keep the first occurrences, to `"last"` to keep the last occurrences, and to `"error"` to raise an informative error and indicate what arguments have duplicated names.
`.check_assign` | Whether to check for `<-` calls passed in dots. When `TRUE` and a `<-` call is detected, a warning is issued to advise users to use `=` if they meant to match a function parameter, or wrap the `<-` call in braces otherwise. This ensures assignments are explicit.

### User expressions versus your expressions

There are two points of view when it comes to capturing an expression:

- You can capture the expressions supplied by the user of your function. This is the purpose of `ensym()`, `enexpr()` and `enquo()` and their plural variants. These functions take an argument name and capture the expression that was supplied to that argument.

- You can capture the expressions that you supply. To this end use `expr()` and `quo()` and their plural variants `exprs()` and `quos()`.

### Capture raw expressions

- `enexpr()` and `expr()` capture a single raw expression.

- `enexprs()` and `exprs()` capture a list of raw expressions including expressions contained in `...`.

- `ensym()` and `ensyms()` are variants of `enexpr()` and `enexprs()` that check the captured expression is either a string (which they convert to symbol) or a symbol. If anything else is supplied they throw an error.

In terms of base functions, `enexpr(arg)` corresponds to `base::substitute(arg)` (though that function also features complex substitution semantics) and `expr()` is like `quote()` (and `bquote()` if we consider unquotation syntax). The plural variant `exprs()` is equivalent to `base::alist()`. Finally there is no function in base R that is equivalent to `enexprs()` but you can reproduce its behaviour with `eval(substitute(alist(...)))`.

### Capture expressions in quosures

`quo()` and `enquo()` are similar to their `expr` counterparts but capture both the expression and its environment in an object called a quosure. This wrapper contains a reference to the original environment in which that expression was captured. Keeping track of the environments of expressions is important because this is where functions and objects mentioned in the expression are defined.

Quosures are objects that can be evaluated with `eval_tidy()` just like symbols or function calls. Since they always evaluate in their original environment, quosures can be seen as vehicles that allow expressions to travel from function to function but that beam back instantly to their original environment upon evaluation.

See the quosure help topic about tools to work with quosures.

### Quasiquotation

All quotation functions in rlang have support for unquoting operators. The combination of quotation and unquotation is called quasiquotation.

Unquotation provides a way to refer to variables during quotation. Variables are problematic when quoting because a captured expression is essentially a constant, just like a string is a constant. For instance in all the following cases `apple` is a constant: `~apple`, `"apple"` and `expr(apple)`. Unquoting allows you to introduce a part of variability within a captured expression.

- In the case of `enexpr()` and `enquo()`, unquoting provides an escape hatch to the users of your function that allows them to manipulate the expression that you capture.

- In the case of `expr()` and `quo()`, quasiquotation lets you build a complex expressions where some parts are constant (the parts that are captured) and some parts are variable (the parts that are unquoted).

See the quasiquotation help topic for more about this as well as the chapter in Advanced R.

### Examples

    # expr() and exprs() capture expressions that you supply:
    expr(symbol)
    exprs(several, such, symbols)

    # enexpr() and enexprs() capture expressions that your user supplied:
    expr_inputs <- function(arg, ...) {
      user_exprs <- enexprs(arg, ...)
      user_exprs
    }
    expr_inputs(hello)
    expr_inputs(hello, bonjour, ciao)

    # ensym() and ensyms() provide additional type checking to ensure
    # the user calling your function has supplied bare object names:
    sym_inputs <- function(...) {
      user_symbols <- ensyms(...)
      user_symbols
    }
    sym_inputs(hello, "bonjour")
    ## sym_inputs(say(hello))  # Error: Must supply symbols or strings
    expr_inputs(say(hello))

    # All these quoting functions have quasiquotation support. This
    # means that you can unquote (evaluate and inline) part of the
    # captured expression:
    what <- sym("bonjour")
    expr(say(what))
    expr(say(!!what))

    # This also applies to expressions supplied by the user. This is
    # like an escape hatch that allows control over the captured
    # expression:
    expr_inputs(say(!!what), !!what)

    # Finally, you can capture expressions as quosures. A quosure is an
    # object that contains both the expression and its environment:
    quo <- quo(letters)
    quo

    get_expr(quo)
    get_env(quo)

    # Quosures can be evaluated with eval_tidy():
    eval_tidy(quo)

    # They have the nice property that you can pass them around from
    # context to context (that is, from function to function) and they
    # still evaluate in their original environment:
    multiply_expr_by_10 <- function(expr) {
      # We capture the user expression and its environment:
      expr <- enquo(expr)

      # Then create an object that only exists in this function:
      local_ten <- 10

      # Now let's create a multiplication expression that (a) inlines
      # the user expression as LHS (still wrapped in its quosure) and
      # (b) refers to the local object in the RHS:
      quo(!!expr * local_ten)
    }
    quo <- multiply_expr_by_10(2 + 3)

    # The local parts of the quosure are printed in colour if your
    # terminal is capable of displaying colours:
    quo

    # All the quosures in the expression evaluate in their original
    # context. The local objects are looked up properly and we get the
    # expected result:
    eval_tidy(quo)

[Package rlang version 0.4.1 Index]