class: center, middle, inverse, title-slide # Chapter 17: Metaprogramming, Big Picture ## Tony ElHabr ### R4DS Reading Group --- <style> hide { display: none; } .remark-slide-content h1 { font-size: 45px; } h1 { font-size: 2em; margin-block-start: 0.67em; margin-block-end: 0.67em; } .remark-slide-content { font-size: 16px } .remark-code { font-size: 14px; } code.r { font-size: 14px; } pre { margin-top: 0px; margin-bottom: 0px; } .red { color: #FF0000; } .blue { color: #0000FF; } .green { color: #00EE00; } .footnote { color: #800020; font-size: 10px; } .aligncenter { text-align: center; } .remark-slide-number { display: none; } </style> # What is metaprogramming? -- <img src="img/cake-meme-1.JPG" width="100%" style="display: block; margin: auto auto auto 0;" /> --- # What is metaprogramming? <img src="img/cake-meme-2.JPG" width="100%" style="display: block; margin: auto auto auto 0;" /> --- # What is metaprogramming? <img src="img/cake-meme-3.JPG" width="100%" style="display: block; margin: auto auto auto 0;" /> --- # What is metaprogramming? <img src="img/cake-meme-4.JPG" width="100%" style="display: block; margin: auto auto auto 0;" /> --- # What is metaprogramming? -- Writing programs (or code) that can manipulate other programs (or code). -- Does metaprogamming == __Non Standard Evaluation (NSE)__? > [Metaprogramming] is the idea that code is data that can be inspected and modified programmatically... Closely related to metaprogramming is __non-standard evaluation__, NSE for short. This term, which is commonly used to describe the behaviour of R functions, is problematic.. NSE is actually a property of the argument (or arguments) of a function, so talking about NSE functions is a little sloppy. --- # Big Ideas -- <img src="img/big-ideas-meme-1.jpg" width="40%" style="display: block; margin: auto;" /> --- # Big Ideas <img src="img/big-ideas-meme-2.jpg" width="40%" style="display: block; margin: auto;" /> --- # Big Ideas <img src="img/big-ideas-meme-3.jpg" width="40%" style="display: block; margin: auto;" /> --- # Big Ideas <img src="img/big-ideas-meme-4.jpg" width="40%" style="display: block; margin: auto;" /> -- .footnote[ References: (1) https://rstudio.com/resources/rstudioconf-2018/tidy-eval-programming-with-dplyr-tidyr-and-ggplot2/, (2) https://www.youtube.com/watch?v=nERXS3ssntw, (3) https://www.youtube.com/watch?v=g1h-YDWVRLc ] --- # 1. R code is a tree -- <img src="img/code-tree-meme.jpg" width="38%" style="display: block; margin: auto;" /> --- # 1. R code is a tree But what does that mean??? -- ___"R code can be described as expressions, which can be drawn as trees."___ <!-- > Expressions are also called __abstract syntax trees (ASTs)__ because the structure of code is hierarchical and can be naturally represented as a tree.--> > An expression is anything that has a value. The simplest expressions are literal values like the number 1, the string "stuff", and the Boolean TRUE. A variable like least is also an expression: its value is whatever the variable currently refers to. Complex expressions are built out of simpler expressions: `1 + 2` is an expression that uses `+` to combine 1 and 2, while the expression `c(10, 20, 30)` uses the function `c` to create a vector out of the values 10, 20, 30. Expressions are often drawn as trees. .footnote[ https://third-bit.com/2018/11/16/non-standard-evaluation.html ] -- ```r lobstr::ast(f(x, 'y', 1)) ``` ``` ## o-f ## +-x ## +-"y" ## \-1 ``` -- > Colours will be shown when you call `ast()`, but do not appear in the book for complicated technical reasons. <!-- ASTs are not unique to R. However, R is somewhat unique because of how it provides users the freedom to manipulate the tree. --> -- <img src="img/hw.jpg" width="100" height="100" style="display: block; margin: auto;" /> --- # 1. R code is a tree But what does that mean??? ___"R code can be described as expressions, which can be drawn as trees."___ > An expression is anything that has a value. The simplest expressions are literal values like the number 1, the string "stuff", and the Boolean TRUE. A variable like least is also an expression: its value is whatever the variable currently refers to. Complex expressions are built out of simpler expressions: `1 + 2` is an expression that uses `+` to combine 1 and 2, while the expression `c(10, 20, 30)` uses the function `c` to create a vector out of the values 10, 20, 30. Expressions are often drawn as trees. .footnote[ https://third-bit.com/2018/11/16/non-standard-evaluation.html ] ```r lobstr::ast(f(x, 'y', 1)) ``` ``` ## o-f ## +-x ## +-"y" ## \-1 ``` > Colours will be shown when you call `ast()`, but do not appear in the book for complicated technical reasons. <img src="img/troll-meme.png" width="100" height="100" style="display: block; margin: auto;" /> --- # 1. R code is a tree Everything is a tree! -- .pull-left[ Assignment and infix operator (`*`) ```r x <- 1 lobstr::ast(y <- 2 * x) ``` ``` ## o-`<-` ## +-y ## \-o-`*` ## +-2 ## \-x ``` Control flow statements ```r lobstr::ast(if(x > 1) y else x) ``` ``` ## o-`if` ## +-o-`>` ## | +-x ## | \-1 ## +-y ## \-x ``` ] -- .pull-right[ Functions ```r lobstr::ast(function(x, y) x + y) ``` ``` ## o-`function` ## +-o-x = `` ## | \-y = `` ## +-o-`+` ## | +-x ## | \-y ## \-<inline srcref> ``` ASTs ```r lobstr::ast(lobstr::ast(x + y)) ``` ``` ## o-o-`::` ## | +-lobstr ## | \-ast ## \-o-`+` ## +-x ## \-y ``` ] --- # 2. Capture trees by __quoting__ -- ```r ex1 <- rlang::expr(x + y) ex1 ``` ``` ## x + y ``` -- ```r x <- 1 y <- 2 eval(ex1) ``` ``` ## [1] 3 ``` ```r lobstr::ast(1 + 2) ``` ``` ## o-`+` ## +-1 ## \-2 ``` --- # 2. Capture trees by __quoting__ -- `rlang::expr` vs. `rlang::enexpr` -- `rlang::expr` quotes __your__ expression ```r f1 <- function(z) expr(z) f1(a + b) ``` ``` ## z ``` -- `enexpr` quotes __user's__ expression ```r f2 <- function(z) enexpr(z) f2(a + b) ``` ``` ## a + b ``` -- `en` = "enriched" --- # 2. Capture trees by __quoting__ <img src="img/expr-enexpr-meme.jpg" width="44%" style="display: block; margin: auto;" /> --- # 2. Capture trees by __quoting__ <code class ='r hljs remark-code'>mean(<span style='color:blue'>x + y</span>)<br><br>library(<span style='color:red'>ggplot2</span>) <br><br># ggplot(<span style='color:blue'>mtcars</span>, aes(<span style='color:red'>disp</span>, <span style='color:red'>mpg</span>)) + geom_point()<br><br><span style='color:blue'>mtcars</span>$<span style='color:red'>disp</span><br><br><span style='color:red'>z</span> <- <span style='color:blue'>x + 1</span><br><br>data.frame(<span style='color:red'>z</span> = <span style='color:blue'>3</span>)</code> .blue[Blue]: Evaluated using usual R rules .red[Red]: Quoted and evaluated with special rules --- # 3. Build trees by __unquoting__ -- ```r lobstr::ast(eval(!!ex1)) ``` ``` ## o-eval ## \-o-`+` ## +-x ## \-y ``` -- ```r ex2 <- rlang::expr(x / !!ex1) ex2 ``` ``` ## x/(x + y) ``` -- ```r eval(ex2) ``` ``` ## [1] 0.3333333 ``` -- ```r lobstr::ast(eval(!!ex2)) ``` ``` ## o-eval ## \-o-`/` ## +-x ## \-o-`+` ## +-x ## \-y ``` --- # 3. Build trees by __unquoting__ Understanding how to build code trees == success in online arguments. <img src="img/pjmdoll-tweet.jpg" width="60%" style="display: block; margin: auto;" /> --- # 3. Build trees by __unquoting__ Understanding how to build code trees == success in online arguments. <img src="img/pjmdoll-tweet-w-reply-1.jpg" width="60%" style="display: block; margin: auto;" /> --- # 3. Build trees by __unquoting__ Understanding how to build code trees == success in online arguments. <img src="img/pjmdoll-tweet-w-reply-2.jpg" width="60%" style="display: block; margin: auto;" /> --- # 3. Build trees by __unquoting__ Understanding how to build code trees == success in online arguments. <!-- `lobstr::ast()` does not actually evaluate! --> ```r x <- 8 / 2 * (2 + 2) ``` ```r lobstr::ast(x <- 8 / 2 * (2 + 2)) ``` ``` ## o-`<-` ## +-x ## \-o-`*` ## +-o-`/` ## | +-8 ## | \-2 ## \-o-`(` ## \-o-`+` ## +-2 ## \-2 ``` ```r x ``` ``` ## [1] 16 ``` --- # 4. Capture trees __AND__<br /> environments -- __quosure__ == closure + quote -- __Quosures__ aremportant for disambiguating the context in which expressions are evaluated (e.g. a column in a data frame or a variable in the parent environment). --- # 4. Capture trees __AND__<br /> environments Result is `tibble(x = 0, y = 1)`. <code class ='r hljs remark-code'>update <- function(df, col) {<br> <span style='background-color:yellow'>n <- 1</span><br> col <- <span style='background-color:white'>rlang::enexpr</span>(col)<br> res <- dplyr::mutate(df, y = !!col)<br> res<br>}<br><br>df <- tibble::tibble(x = 0)<br><span style='background-color:pink'>n <- 2</span><br>update(df, <span style='background-color:yellow'>x + n</span>)</code> --- # 4. Capture trees __AND__<br /> environments <img src="img/quosure-incorrect-meme.png" width="80%" style="display: block; margin: auto;" /> --- # 4. Capture trees __AND__<br /> environments Result is `tibble(x = 0, y = 2)`. <code class ='r hljs remark-code'>update <- function(df, col) {<br> <span style='background-color:pink'>n <- 1</span><br> col <- <span style='background-color:white'>rlang::enquo</span>(col)<br> res <- dplyr::mutate(df, y = !!col)<br> res<br>}<br><br>df <- tibble::tibble(x = 0)<br><span style='background-color:yellow'>n <- 2</span><br>update(df, <span style='background-color:yellow'>x + n</span>)</code> --- # 4. Capture trees __AND__<br /> environments <img src="img/contrived-canonical-example.jpg" width="60%" style="display: block; margin: auto;" /> --- # The Power of Metaprogramming -- Metaprogramming is awesome. R is great because of how much control it allows user to have. -- <img src="img/when-non-tech-people-ask-me-to-describe-my-job.gif" width="44%" style="display: block; margin: auto;" /> --- # What's next + Chapter 18: More about R code as a tree + Chapter 19: More about evaluating (quoting) unevaluated code + Chapter 20: More about evaluating (unquoting) captured code --- # Aside about trees -- Understanding how "code is a tree" would have helped me with my final project in my Intro to Programming class. -- .pull-left[ <img src="img/final-lab-1.jpg" width="100%" style="display: block; margin: auto;" /> ] .pull-right[ > Please note that whether you choose to explicitly build a parse tree or not, you will almost certainly have to write your parsing and executing function(s) using recursion. Fortunately, the recursion required to do this is super easy (whether you build a parse tree or not, the recursion is very natural). <br /> > Implementing a Parse Tree is optional for Phase A. In Phase B, we will almost certainly mandate that you have a Parse Tree, and for Phase B, the parse trees are decidedly more complicated, since you will have both Expressions to represent and Statements to represent. ] --- # Aside about trees .pull-left[ <img src="img/final-lab-2.jpg" width="100%" style="display: block; margin: auto;" /> ] -- .pull-right[ <br /> <img src="img/mario-meme.JPG" width="90%" style="display: block; margin: auto;" /> ]