elixir
is primarily a package for working with what it calls
"expressions", in the sense of any R object for which
rlang::is_expression()
returns TRUE
. This includes calls, like the
results of evaluating quote(f(x))
or quote(a:b)
, symbols like
quote(z)
, and syntactic literals like 2.5
, "hello"
, NULL
, FALSE
,
and so on.
This is not to be confused with the built-in type base::expression, which
is essentially a special way of storing a vector of multiple "expressions".
elixir
does not use this type; see expr_list()
instead.
Specifying expressions in elixir
The elixir
package functions starting with expr_
work with expressions.
These functions all accept a special (optional) syntax for specifying
expressions which involves the symbols {}
, ?
, and ~
, as well as the
rlang injection operator, !! and
splice operator, !!!).
With base R, if you want to store an expression such as x + y
in a
variable or pass it to a function, you need to use base::quote()
or
rlang::expr()
, but any Elixir expr_
function will also accept an
"expression literal" wrapped in braces, {}
.
So, for example, rather than
translate(quote(x ^ y), "C++")
you can write
translate({ x ^ y }, "C++")
.
This only works if the braces are provided "directly"; that is, in
expr <- quote({ x ^ y }); translate(expr, "C++")
,
the braces are not interpreted in any special way.
Anything between the braces essentially gets put through rlang::expr()
, so
you can use !!
(i.e. rlang::injection-operator) and !!!
(i.e.
rlang::splice-operator). There is an env
parameter to all relevant
elixir
functions, defaulting to parent.frame()
, in which these injection
operations are evaluated.
Special syntax for patterns and replacements
Additionally, some functions (expr_match()
, expr_count()
,
expr_detect()
, expr_extract()
, expr_locate()
, and expr_replace()
)
take pattern
and/or replacement
arguments to specify patterns to match
to an expression and/or replacement expressions to replace those matches
with.
For both pattern
and replacement
arguments, you can use the question
mark operator ?
to specify alternatives. For example, to match either
the token cat
or dog
, you can use
expr_match(expr, { cat } ? { dog })
.
You can chain together as many alternatives as are needed. Alternatively,
if you have a list of expressions z
, you can use a single question mark
before the name of the list, like so:
expr_match(expr, ?z)
and elixir
will treat the list as a set of alternatives. When using
expr_replace()
with a set of alternatives as the pattern, the replacement
needs to be either a single expression, or a set of alternative expressions
which has the same number of alternatives as in the pattern.
You can also use the tilde operator ~
to specify that a given pattern
should be "anchored" at the top level of an expression, and will not
"recurse into" the expression. For example, in
only the numbers 2
and 5
will match. However, in
all numbers 2
, 5
, 1
and 4
will match, because the pattern
can
recurse into the third expression 1 + 4
.