Skip to content

Instantly share code, notes, and snippets.

@wch
Last active November 13, 2020 19:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wch/812f7c6bb0f9c5b7d73194e3e5cbf758 to your computer and use it in GitHub Desktop.
Save wch/812f7c6bb0f9c5b7d73194e3e5cbf758 to your computer and use it in GitHub Desktop.
rlang::new_function() and rlang::as_function() with nested quosures
library(rlang)
library(pryr)
# ===========================
# Normal quosures
# ===========================
# as_function() with a quosure: OK
a <- 1
x <- quo(a + 10)
a <- 2
f <- as_function(x)
parenvs(f)
#> label name
#> 1 <environment: 0x7f9f34b01e48> ""
#> 2 <environment: R_GlobalEnv> ""
stopifnot(identical(f(), 12))
# new_function() with expr and env extracted from quosure: OK
a <- 1
x <- quo(a + 10)
a <- 2
f <- new_function(NULL, get_expr(x), get_env(x))
parenvs(f)
#> label name
#> 1 <environment: R_GlobalEnv> ""
stopifnot(identical(f(), 12))
# ===========================
# Nested quosures
# ===========================
# as_function() with nested quosures: OK
a <- 1
y <- quo(a)
x <- quo(!!y + 10)
a <- 2
f <- as_function(x)
parenvs(f)
#> label name
#> 1 <environment: 0x7f9f643eaa10> ""
#> 2 <environment: R_GlobalEnv> ""
stopifnot(identical(f(), 12))
# new_function() with expr and env extracted from nested quosure: Error
a <- 1
y <- quo(a)
x <- quo(!!y + 10)
a <- 2
f <- new_function(NULL, get_expr(x), get_env(x))
parenvs(f)
#> label name
#> 1 <environment: R_GlobalEnv> ""
stopifnot(identical(f(), 12))
#> Error: Base operators are not defined for quosures.
#> Do you need to unquote the quosure?
#>
#> # Bad:
#> myquosure + rhs
#>
#> # Good:
#> !!myquosure + rhs
# Look at the contents of x
z <- get_expr(x)
z
#> (~a) + 10
z[[2]] # A quosure is part of the AST
#> <quosure>
#> expr: ^a
#> env: global
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment