class: center, middle, inverse, title-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 --- class: left, top ## Intro What if we want to run a defined code but don't actually have the input yet! ```r 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. ```r (Expression <- rlang::expr(Result <- a + b)) ``` ``` ## Result <- a + b ``` -- The previous generated **Expression** can be evaluated (`eval`): ```r a <- b <- 1 eval(Expression) Result ``` ``` ## [1] 2 ``` --- class: left, top ## 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.** --- class: left, top ### Quosure Quoted expression that includes a reference to the context where it was created. ```r 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 ``` ```r eval_tidy(quo) ``` ``` ## [1] 20 ``` --- class: left, top ## ASTs Review Package lobstr `ast` ```r lobstr::ast(f(x, "y", 1)) ``` ``` ## █─f ## ├─x ## ├─"y" ## └─1 ``` RStudio TreeViewer ```r View(expr(f(x, "y", 1))) ``` <img src="data:image/png;base64,#./img/view_expression.png" width="" style="display: block; margin: auto;" /> --- class: left, top ## ASTs Syntax ```r lobstr::ast(f(g(1, 2), h(3, 4, i()))) ``` <img src="data:image/png;base64,#https://d33wubrfki0l68.cloudfront.net/9e269a7eb3509ae2e9f3fa9583ff2195b947cc53/d5886/diagrams/expressions/complicated.png" width="50%" style="display: block; margin: auto;" /> - Evaluation from deepest-to-shallowest (not guaranteed) - Abstract Syntax: white space and comments are ignored - exception: `y <- x` != `y < -x` --- class: left, top #### Inside - Out Example ```r 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): ```r 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 | --- class: left, top ## Infix Calls - Does not matter how you write it: function or infix ```r expr(y <- x * 10) ``` ``` ## y <- x * 10 ``` ```r expr(`<-`(y, `*`(x, 10))) ``` ``` ## y <- x * 10 ``` <img src="data:image/png;base64,#https://d33wubrfki0l68.cloudfront.net/e32631051094207bc971e4352744db7ba6f8aac1/6f551/diagrams/expressions/prefix.png" width="50%" style="display: block; margin: auto;" /> --- class: left, top ## Expression Data Types - **constants**, expression of a constant is the same as outside of the expression ```r expr(1) == 1 ``` ``` ## [1] TRUE ``` - **symbols**, represents name of an object ```r x <- 1 expr(x) == sym("x") ``` ``` ## [1] TRUE ``` ```r expr(x) == x ``` ``` ## [1] FALSE ``` ```r # Reverse rlang::as_string(expr(x)) ``` ``` ## [1] "x" ``` --- class: left, top ## Calls - **call object** represents a captured function call - type of list (pairlist to be precise) ```r lobstr::ast(f(a = 1, b = 2)) ``` ``` ## █─f ## ├─a = 1 ## └─b = 2 ``` ```r is.call(expr(f(a = 1, b = 2))) ``` ``` ## [1] TRUE ``` --- class: left, top ## Manipulating Expressions ```r x <- expr(f(a = 1, b = 2)) x[[1]] ``` ``` ## f ``` ```r x[[2]] ``` ``` ## [1] 1 ``` ```r x$a <- 3 x ``` ``` ## f(a = 3, b = 2) ``` --- class: left, top ## Constructing ```r call2("<-", expr(x), 10) ``` ``` ## x <- 10 ``` ```r 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. --- class: center, middle <img src="data:image/png;base64,#./img/parse.jpg" width="" style="display: block; margin: auto;" /> --- class: left, top ## Parsing ```r x1 <- "2 + 10" eval(x1) # Eval wont work as it is still a string ``` ``` ## [1] "2 + 10" ``` ```r (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): ```r (p2 <- parse(text = x1)) ``` ``` ## expression(2 + 10) ``` ```r (eval(p1)) == (eval(p2)) ``` ``` ## [1] TRUE ``` --- class: left, top ## Deparsing - given an expression, you want the string that would generate it ```r z <- expr(1+2) expr_text(z) ``` ``` ## [1] "1 + 2" ``` - does happen when we print the expression automatically ```r print(z) ``` ``` ## 1 + 2 ``` --- class: center, middle <img src="data:image/png;base64,#./img/eval_evil.jpeg" width="" style="display: block; margin: auto;" />