Skip to contents

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.

Usage

expr_list(number = { `.A:numeric` } ? { `.A:integer` },
    string = { `.A:character` }, symbol = { `.A:name` })
expr_match({ 1 * 2 }, ~{ .A * .B })
expr_match({ 1 * 2 }, { `.A:numeric` })
expr_replace({ y = a*x^3 + b*x^2 + c*x^1 + d*x^0 },
    { ..X ^ ..N }, { pow(..X, ..N) })

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

exprs = expr_list(2, 5, {1 + 4})
expr_match(exprs, ~{ `.A:numeric` })

only the numbers 2 and 5 will match. However, in

exprs = expr_list(2, 5, {1 + 4})
expr_match(exprs, { `.A:numeric` })

all numbers 2, 5, 1 and 4 will match, because the pattern can recurse into the third expression 1 + 4.