knitr::opts_chunk$set(
  eval = TRUE,
  collapse = TRUE,
  comment = "#>"
)
suppressWarnings({
  library(rlang)
  library(lobstr)
  library(tibble)
  library(dplyr, warn.conflicts = FALSE)
  library(palmerpenguins)
})

These notes were made whilst reading the metaprogramming chapters 17 - 20 in Hadley Wickham's Advanced R book.

Additional resources

environment

# symbol assigned with a constant in the global environment
species_name <- "Gentoo"
gender <- "male"

# symbol assigned with a constant in a tibble in the global environment
data_tibble <- tibble(species_name = "Chinstrap",
                      gender = "female")

# create a new data environment
penguin_environment <- env()

# symbol assigned with a constant in the data environment
assign("species_name", "Adelie", envir = penguin_environment)
assign("gender", "unknown", envir = penguin_environment)

expression

# view expression as abstract syntax tree
ast(function_name <- function(parameter = "Gentoo"){
  return(parameter_value)
  })

quasiquotation

Ability to both capture an expression without evaluation using quotation and selectively evaluating part of this quoted expression using unquotation

quotation (parsing): capturing an expression without evaluating it

# parse constant string as an expression
parse_expr('species_name <- "Gentoo"')

# parse symbol name as an expression
expr(species_name) # base equivalent = quote(species_name)

# parse multiple symbols names as a list of expressions
exprs(species_name, gender) # base equivalent = alist(species_name, gender)

# parse symbol's assigned constant as an expression 
enexpr(species_name) # base equivalent = substitute(species_name)

# parse multiple symbol's assigned constants as an expression
enexprs(species_name, gender)

# parse multiple constant arguments in function passed using ...
data <- function(...) {
  enexprs(...) # base equivalent = as.list(substitute(...()))
}
data(species_name = "Gentoo", gender = "male")

# quosure - capture symbol name as expression along with its environment
quo(species_name)

# quosures - capture list of symbol names as expression along with its environment
quos(species_name, gender)

# quosure - capture symbol's assigned constant  as an expression along with its environment
enquo(species_name)

# quosures - capture a list of symbol's assigned constants as expressions along its their environment
enquos(species_name, gender)

quotation (parsing): capturing a symbol without evaluating it

# convert a string constant into a symbol
sym("species_name")

# parse symbols assigned symbol as an expression
ensym(species_name)

# parse multiple symbols assigned symbols as an expression
ensyms(species_name, gender)

# parse multiple symbol arguments in function passed using ...
data <- function(...) {
  ensyms(...)
}
data(species_name = Gentoo, gender = male)

unquoting: selectively evaluating part of a quoted expression

# evaluate part of the expression using the unquote operator !!
expr(!!expr(species_name) <- !!enexpr(species_name))
expr(!!sym("gender") <- !!enexpr(gender))

# evaluate multiple symbols names stored as a list of expressions
expr(f(!!!exprs(species_name, gender)))

deparsing: construct a string from an expression

# convert a symbol into a string constant
expr_text(expr(species_name)) # base equivalent = deparse(quote(species_name))

evaluation

evaluation of an expression

# evaluate a symbol expression assigned to a constant within a specified environment
eval(expr = expr(species_name))
eval(expr = expr(species_name), envir = penguin_environment)

evaluation of a quosure

eval_tidy(expr = enquo(species_name))

evaluation of an expression in the context of a data frame (data mask)

eval_tidy(expr = expr(species_name), data = data_tibble)

examples

get_maximum_value <- function(data, category, variable) {

  # quosure containing parameter's value as an expression and its environment
  category <- enquo(category) # species
  variable <- enquo(variable) # body_mass_g

  # evaluate quosure using the unquote operator
  data |>
    group_by(!!category) |>
    summarise(maximum = max(!!variable, na.rm = TRUE))
}
penguins |> 
  get_maximum_value(category = species, 
                    variable = body_mass_g)
# {{ }} is a short hand replacement for !!(enquo(x))
get_maximum_value <- function(data, category, variable) {

  # create and unquote quosure containing parameter's value as an expression and its environment using {{ }}
  data |> 
    group_by({{category}}) |> 
    summarise(maximum = max({{variable}}, na.rm = TRUE))
}
penguins |> 
  get_maximum_value(category = species, 
                    variable = body_mass_g)
get_maximum_value <- function(data, category, ...) {

  # create and unquote multiple quosures using ...
  data |> 
    group_by({{category}}) |> 
    summarise(...)
}
penguins |> 
  get_maximum_value(category = species, 
                    average = mean(body_mass_g, na.rm = TRUE),
                    maximum = max(body_mass_g, na.rm = TRUE))
get_maximum_value <- function(data, category, variable) {

  # use := to quote and unquote on left hand side of =
  data |>
    group_by({{category}}) |>
    summarise("{{category}}_maximum" := max({{variable}}, na.rm = TRUE))
}
penguins |> 
  get_maximum_value(category = species, 
                    variable = body_mass_g)
get_maximum_value <- function(data, category, variable, unit) {

  # use {} to add string and := to quote and unquote on left hand side of =
  data |>
    group_by({{category}}) |>
    summarise("maximum_{unit}" := max({{variable}}, na.rm = TRUE))
}
penguins |> 
  get_maximum_value(category = species, 
                    variable = body_mass_g,
                    unit = "gram")
# .data[[ ]] pronoun is used when parameter values are strings, to distinguish from using environment constant values identified by the .env pronoun 
get_maximum_value <- function(data, category, variable) {

  # create and unquote quosure containing parameter's value as an expression and its environment using {{ }}
  data |> 
    group_by(.data[[category]]) |> 
    summarise(maximum = max(.data[[variable]], na.rm = TRUE))
}
penguins |> 
  get_maximum_value(category = "species", 
                    variable = "body_mass_g")


gcfrench/store documentation built on May 17, 2024, 5:52 p.m.