+ - 0:00:00
Notes for current slide
Notes for next slide

Advanced R - Expressions

eval is Evil, The eval function is the most misused feature of JavaScript. Avoid it. - Evan Crockford

Hannes Oberreiter

Cohort 5

1 / 16

Intro

What if we want to run a defined code but don't actually have the input yet!

try(Result <- a + b)
## Error in try(Result <- a + b) : object 'a' not found
2 / 16

Intro

What if we want to run a defined code but don't actually have the input yet!

try(Result <- a + b)
## Error in try(Result <- a + b) : object 'a' not found

We need first to capture our code into an Expression, so it wont be executed straight away.

(Expression <- rlang::expr(Result <- a + b))
## Result <- a + b
2 / 16

Intro

What if we want to run a defined code but don't actually have the input yet!

try(Result <- a + b)
## Error in try(Result <- a + b) : object 'a' not found

We need first to capture our code into an Expression, so it wont be executed straight away.

(Expression <- rlang::expr(Result <- a + b))
## Result <- a + b

The previous generated Expression can be evaluated (eval):

a <- b <- 1
eval(Expression)
Result
## [1] 2
2 / 16

Expression and Evaluation Notes

  • expr() and enquo() prevents evaluation (defusing, quoting)
    • enquo() defuses expressions supplied as argument by the user of a function
    • base: quote() and substitute()
  • eval_tidy() evaluation of an saved expression
    • base: eval()

The process by which a computer language takes a string and constructs an expression is called parsing, and is governed by a set of rules known as a grammar.

3 / 16

Quosure

Quoted expression that includes a reference to the context where it was created.

multiply_expr_by_10 <- function(expr) {
expr <- enquo(expr)
local_ten <- 10
quo(!!expr * local_ten)
}
quo <- multiply_expr_by_10(a + b)
quo
## <quosure>
## expr: ^(^a + b) * local_ten
## env: 0x7fcd93ecd300
eval_tidy(quo)
## [1] 20
4 / 16

ASTs Review

Package lobstr ast

lobstr::ast(f(x, "y", 1))
## █─f
## ├─x
## ├─"y"
## └─1

RStudio TreeViewer

View(expr(f(x, "y", 1)))

5 / 16

ASTs Syntax

lobstr::ast(f(g(1, 2), h(3, 4, i())))

  • Evaluation from deepest-to-shallowest (not guaranteed)
  • Abstract Syntax: white space and comments are ignored
    • exception: y <- x != y < -x
6 / 16

Inside - Out Example

sum(10 * sum(1+1+1), mean(c((1+1), 4)))
## [1] 33
  • most operators are left-associative, i.e. the operations on the left are evaluated first (expections: exponentiation and assignment):
lobstr::ast(1 + 2 + 3) # ( 1 + 2 ) + 3
## █─+
## ├─█─+
## │ ├─1
## │ └─2
## └─3
operator meaning associativity
:: ::: access variables in a namespace left-associative
$ @ component / slot extraction left-associative
[ [[ indexing left-associative
^ exponentiation (right to left) right-associative
7 / 16

Infix Calls

  • Does not matter how you write it: function or infix
expr(y <- x * 10)
## y <- x * 10
expr(<-(y, *(x, 10)))
## y <- x * 10

8 / 16

Expression Data Types

  • constants, expression of a constant is the same as outside of the expression
expr(1) == 1
## [1] TRUE
  • symbols, represents name of an object
x <- 1
expr(x) == sym("x")
## [1] TRUE
expr(x) == x
## [1] FALSE
# Reverse
rlang::as_string(expr(x))
## [1] "x"
9 / 16

Calls

  • call object represents a captured function call
    • type of list (pairlist to be precise)
lobstr::ast(f(a = 1, b = 2))
## █─f
## ├─a = 1
## └─b = 2
is.call(expr(f(a = 1, b = 2)))
## [1] TRUE
10 / 16

Manipulating Expressions

x <- expr(f(a = 1, b = 2))
x[[1]]
## f
x[[2]]
## [1] 1
x$a <- 3
x
## f(a = 3, b = 2)
11 / 16

Constructing

call2("<-", expr(x), 10)
## x <- 10
call2("mean", x = expr(x), na.rm = TRUE)
## mean(x = x, na.rm = TRUE)

Using call2() to create complex expressions is a bit clunky. You’ll learn another technique in Chapter 19.

12 / 16

13 / 16

Parsing

x1 <- "2 + 10"
eval(x1) # Eval wont work as it is still a string
## [1] "2 + 10"
(p1 <- rlang::parse_expr(x1)) # multiple expressions with parse_exprS
## 2 + 10

Base (returns Expression Vector, means it is not a list but a vector of expressions more or less the same):

(p2 <- parse(text = x1))
## expression(2 + 10)
(eval(p1)) == (eval(p2))
## [1] TRUE
14 / 16

Deparsing

  • given an expression, you want the string that would generate it
z <- expr(1+2)
expr_text(z)
## [1] "1 + 2"
  • does happen when we print the expression automatically
print(z)
## 1 + 2
15 / 16

16 / 16

Intro

What if we want to run a defined code but don't actually have the input yet!

try(Result <- a + b)
## Error in try(Result <- a + b) : object 'a' not found
2 / 16
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow