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

Advanced R

Chapter 18: Expressions

Maya Gans

1 / 18

A note on vocabulary

  • Expression
  • Parsing
  • Deparsing
  • Evaluating
ggplot(x = "other_color")

Here's a stab:

An expression is a list of calls, which can be created through parsing text. These expressions can become text again via deparsing

2 / 18

Parsing vs Parser ...?

Parsing is the process of analyzing text made of a sequence of tokens to determine its grammatical structure with respect to a given (more or less) formal grammar. The parser then builds a data structure based on the tokens.

...but we use the parse function to... convert type character to expression?

x2 <- parse(text = "2 * a")
class(x2)
## [1] "expression"

We can parse expressions, simulating how the parser creates expressions before compiling code? Is that right?

3 / 18

The Shiny App

4 / 18

Abstract Syntax Trees

lobstr::ast(
round(
mean(beer_reviews$review_overall)
, 2)
)
## o-round
## +-o-mean
## | \-o-`$`
## | +-beer_reviews
## | \-review_overall
## \-2
lobstr::ast(
if (x == TRUE) {
y <- yes
} else {
y <- no
}
)
## o-`if`
## +-o-`==`
## | +-x
## | \-TRUE
## +-o-`{`
## | \-o-`<-`
## | +-y
## | \-yes
## \-o-`{`
## \-o-`<-`
## +-y
## \-no

Abstract because ( are implicit, and comments aren't included

5 / 18

Constants

rlang::is_syntactic_literal("beer_review")
## [1] TRUE

Constants are self quoting

7 / 18

Symbols

Represent the name of an object. This is not the same as a string!

Using a String

beer_reviews %>%
dplyr::filter(!!"review_overall" >= 5) %>%
dplyr::pull(review_overall) %>%
head()
## [1] 1.5 3.0 3.0 3.0 4.0 3.0

Using a sym

beer_reviews %>%
dplyr::filter(!!sym("review_overall") >= 5) %>%
dplyr::pull(review_overall) %>%
head()
## [1] 5 5 5 5 5 5
8 / 18

Calls

x <- expr(dplyr::filter(beer_reviews, review_overall >= 5))
typeof(x)
## [1] "language"
is.call(x)
## [1] TRUE

Look at arguments in list form

as.list(x[-1])
## [[1]]
## beer_reviews
##
## [[2]]
## review_overall >= 5

Why isn't review_overall >= 5 broken into its sub-components

ast(
dplyr::filter(beer_reviews, review_overall >= 5)
)
## o-o-`::`
## | +-dplyr
## | \-filter
## +-beer_reviews
## \-o-`>=`
## +-review_overall
## \-5
9 / 18

Operator precedence

operator meaning associativity
:: ::: access variables in a namespace left-associative
$ @ component / slot extraction left-associative
[ [[ indexing left-associative
^ exponentiation (right to left) right-associative
- + unary minus and plus left-associative
: sequence operator left-associative
%any% special operators (including %% and %/% left-associative
* / multiply, divide left-associative
+ - (binary) add, subtract left-associative
< > <= >= == != ordering and comparison left-associative
! negation left-associative
& && and left-associative
| || or left-associative
~ as in formulae left-associative
-> ->> rightwards assignment right-associative
<- <<- assignment (right to left) right-associative
= assignment (right to left) right-associative
? help (unary and binary) left-associative
11 / 18

Parsing

turn inputs from text into expressions

inputs <- list(
arg_1 = "x",
arg2 = "na.rm = TRUE"
)
map(inputs, parse_exprs)
## $arg_1
## $arg_1[[1]]
## x
##
##
## $arg2
## $arg2[[1]]
## na.rm = TRUE
12 / 18

Deparsing

Maybe use this for..... warning messages to alert the user their code is trash?

mayas_mean_function <- function(x, y, z) {
stop(paste("lol you seriously tried to ",
expr_label(quote(x + y + z))))
}
mayas_mean_function(1, 3, 2)
Error in mayas_mean_function(1, 3, 2) : lol you seriously tried to `x + y + z`

How would we build on this to actually return the users specified values?

13 / 18

Walking AST with Recursion

...But can we use recursion to BUILD an AST?

Once the application is working I figured that THIS is theoretically the way we could create and allow the user to nest functions, creating more complicated trees than mean(x, na.rm = TRUE)?

func_1 <- "mean"
arg1_1 <- expr("x")
arg1_2 <- expr("na.rm = TRUE")
func_2 <- "round"
arg2_1 <- expr(call(func_1, arg1_1, arg1_2))

Then somehow put those arguments together to get:

ast(round(mean(x, na.rm = TRUE)))
## o-round
## \-o-mean
## +-x
## \-na.rm = TRUE
14 / 18

Pairlist and missing arguments

Behind the scenes pairlists are implemented using a different data structure, a linked list instead of an array.

f <- expr(function(z, y = 10) z + y)
str(f[[2]])
## Dotted pair list of 2
## $ z: symbol
## $ y: num 10
f_list <- list(
z = missing_arg(),
y = 10
)
str(f_list)
## List of 2
## $ z: symbol
## $ y: num 10

Maybe we use missing_arg() in our shiny application where we create a function with x empty spaces, then use subsetting on our call to replace the missing arguments with the user supplied arguments?

...What's a linked-list?

16 / 18

Expression vectors

Maybe we want to use parse instead of parse_exps? Not sure why this would be preferable, but hey, here's another way

parse(text = c(inputs))
## expression(x, na.rm = TRUE)
17 / 18
18 / 18

A note on vocabulary

  • Expression
  • Parsing
  • Deparsing
  • Evaluating
ggplot(x = "other_color")

Here's a stab:

An expression is a list of calls, which can be created through parsing text. These expressions can become text again via deparsing

2 / 18
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