To compute on the language, we first need to understand its structure. That requires some new vocabulary, some new tools, and some new ways of thinking about R code. The first of these is the distinction between an operation and its result. Take the following code, which multiplies a variable
x by 10 and saves the result to a new variable called
y. It doesn’t work because we haven’t defined a variable called
x * 10 y <-#> Error in eval(expr, envir, enclos): object 'x' not found
It would be nice if we could capture the intent of the code without executing it. In other words, how can we separate our description of the action from the action itself?
One way is to use
rlang::expr(y <- x * 10) z <- z#> y <- x * 10
expr() returns an expression, an object that captures the structure of the code without evaluating it (i.e. running it). If you have an expression, you can evaluate it with
4 x <-eval(z) y#>  40
The focus of this chapter is the data structures that underlie expressions. Mastering this knowledge will allow you to inspect and modify captured code, and to generate code with code. We’ll come back to
expr() in Chapter 19, and to
eval() in Chapter 20.
Section 18.2 introduces the idea of the abstract syntax tree (AST), and reveals the tree like structure that underlies all R code.
Section 18.3 dives into the details of the data structures that underpin the AST: constants, symbols, and calls, which are collectively known as expressions.
Section 18.4 covers parsing, the act of converting the linear sequence of character in code into the AST, and uses that idea to explore some details of R’s grammar.
Section 18.5 shows you how you can use recursive functions to compute on the language, writing functions that compute with expressions.
Section 18.6 circles back to three more specialised data structures: pairlists, missing arguments, and expression vectors.