The vignette demonstrates the use of let
to standardize calls to functions that use non-standard evaluation. For a more formal description please see here.
For the purposes of this discussion, standard evaluation of variables preserves referential transparency: that is, values and references to values behave the same.
= 5
x print(5 + 1)
## [1] 6
print(x + 1)
## [1] 6
Some functions in R use non-standard evaluation (NSE) of variables, in order to snoop variable names (for example, plot
), or to delay or even avoid argument evaluation (for example library(foobar)
versus library("foobar")
).
In the case of plot
, NSE lets plot
use the variable names as the axis labels.
set.seed(1234)
= runif(100) - 0.5
xvar = dnorm(xvar)
yvar
plot(xvar, yvar)
In the case of library
, non-standard evaluation saves typing a couple of quotes. The dollar sign notation for accessing data frame columns also uses non standard evaluation.
<- data.frame(x=c(1,NA))
d $x d
## [1] 1 NA
Issues arise when you want to use functions that use non-standard evaluation – for brevity, I’ll call these NSE expressions – but you don’t know the name of the variable, as might happen when you are calling these expression from within another function. Generally in these situations, you are taking the name of the desired variable from a string. But how do you pass it to the NSE expression?
For this discussion, we will demonstrate let
to standardize calling plot
with unknown variables. let
takes two arguments:
Here’s the plot
example again.
library("wrapr")
= "xvar"
xvariable = "yvar"
yvariable let(
c(XVARIABLE=xvariable, YVARIABLE=yvariable),
# since we have the names as strings, we can create a title
{ = paste(yvariable, "vs", xvariable)
title plot(XVARIABLE, YVARIABLE, main=title)
} )
In the above let()
block we are using the alias
-convention that we specify substitution target names (in this case XVARIABLE
and YVARIABLE
) as upper-case analogues of the substitution name values (in this case xvariable
and yvariable
). This convention is very legible and makes it easy to both use value interfaces (as we did in the title paste()
) and name-capturing interfaces (plot()
itself).
Roughly wrapr::let(A, B)
behaves like a syntactic sugar for eval(substitute(B, A))
.
<- 1
a <- 2
b let(c(z=quote(a)), z+b)
## [1] 3
eval(substitute(z+b, c(z=quote(a))))
## [1] 3
However, wrapr::let()
is actually implemented in terms of a de-parse and safe language token substitution.
wrapr::let()
was inspired by gtools::strmacro()
and base::bquote()
, please see here for some notes on macro methods in R
.
For more discussion please see: