Quasiquotation is the mechanism that makes it possible to program
grammars like dplyr. It is enabled in all tidyeval functions, the
most fundamental of which are
Quasiquotation is the combination of quoting an expression while allowing immediate evaluation (unquoting) of part of that expression. We provide both syntactic operators and functional forms for unquoting.
UQ() and the
!! operator unquote their argument. It gets
evaluated immediately in the surrounding context.
UQE() is like
UQ() but retrieves the expression of
quosureish objects. It is a shortcut for
!! get_expr(x). Use this with care: it is potentially unsafe to
discard the environment of the quosure.
UQS() and the
!!! operators unquote and splice their
argument. The argument should evaluate to a vector or an
expression. Each component of the vector is embedded as its own
argument in the surrounding call. If the vector is named, the
names are used as argument names.
UQ(x) UQE(x) "!!"(x) UQS(x)
An expression to unquote.
expr() are quasiquote functions,
the unquote operator, and
UQS() is the unquote splice operator.
These terms have a rich history in Lisp languages, and live on in
modern languages like
# Quasiquotation functions act like base::quote() quote(foo(bar))#> foo(bar)expr(foo(bar))#> foo(bar)quo(foo(bar))#> <quosure: local> #> ~foo(bar)# In addition, they support unquoting: expr(foo(UQ(1 + 2)))#> foo(3)expr(foo(!! 1 + 2))#> foo(3)quo(foo(!! 1 + 2))#> <quosure: local> #> ~foo(3)# The !! operator is a handy syntactic shortcut for unquoting with # UQ(). However you need to be a bit careful with operator # precedence. All arithmetic and comparison operators bind more # tightly than `!`: quo(1 + !! (1 + 2 + 3) + 10)#> <quosure: local> #> ~1 + 16# For this reason you should always wrap the unquoted expression # with parentheses when operators are involved: quo(1 + (!! 1 + 2 + 3) + 10)#> <quosure: local> #> ~1 + (6) + 10# Or you can use the explicit unquote function: quo(1 + UQ(1 + 2 + 3) + 10)#> <quosure: local> #> ~1 + 6 + 10# Use !!! or UQS() if you want to add multiple arguments to a # function It must evaluate to a list args <- list(1:10, na.rm = TRUE) quo(mean( UQS(args) ))#> <quosure: local> #> ~mean(1:10, na.rm = TRUE)# You can combine the two var <- quote(xyz) extra_args <- list(trim = 0.9, na.rm = TRUE) quo(mean(UQ(var) , UQS(extra_args)))#> <quosure: local> #> ~mean(xyz, trim = 0.9, na.rm = TRUE)# Unquoting is especially useful for transforming successively a # captured expression: quo <- quo(foo(bar)) quo <- quo(inner(!! quo, arg1)) quo <- quo(outer(!! quo, !!! syms(letters[1:3]))) quo#> <quosure: local> #> ~outer(~inner(~foo(bar), arg1), a, b, c)# Since we are building the expression in the same environment, you # can also start with raw expressions and create a quosure in the # very last step to record the dynamic environment: expr <- expr(foo(bar)) expr <- expr(inner(!! expr, arg1)) quo <- quo(outer(!! expr, !!! syms(letters[1:3]))) quo#> <quosure: local> #> ~outer(inner(foo(bar), arg1), a, b, c)