Recursive Quoted Language Expansion.
oshka - Recursive Quoted Language Expansion
Programmable Non-Standard Evaluation
Non-Standard Evaluation (NSE hereafter) occurs when R expressions are captured and evaluated in a manner different than if they had been executed without intervention. subset
is a canonical example, which we use here with the built-in iris
data set:
subset(iris, Sepal.Width > 4.1)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 16 5.7 4.4 1.5 0.4 setosa
## 34 5.5 4.2 1.4 0.2 setosa
Sepal.Width
does not exist in the global environment, yet this works because subset
captures the expression and evaluates it within iris
.
A limitation of NSE is that it is difficult to use programmatically:
exp.a <- quote(Sepal.Width > 4.1)
subset(iris, exp.a)
## Error in subset.data.frame(iris, exp.a): 'subset' must be logical
oshka::expand
facilitates programmable NSE, as with this simplified version of subset
:
subset2 <- function(x, subset) {
sub.exp <- expand(substitute(subset), x, parent.frame())
sub.val <- eval(sub.exp, x, parent.frame())
x[!is.na(sub.val) & sub.val, ]
}
subset2(iris, exp.a)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 16 5.7 4.4 1.5 0.4 setosa
## 34 5.5 4.2 1.4 0.2 setosa
expand
is recursive:
exp.b <- quote(Species == 'virginica')
exp.c <- quote(Sepal.Width > 3.6)
exp.d <- quote(exp.b & exp.c)
subset2(iris, exp.d)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 118 7.7 3.8 6.7 2.2 virginica
## 132 7.9 3.8 6.4 2.0 virginica
We abide by R semantics so that programmable NSE functions are almost identical to normal NSE functions, with programmability as a bonus.
Documentation
- Intro vignette for a more in depth introduction to
oshka
, including a brief comparison torlang
. - NSE Functions with
oshka
in which we recreate simplified versions ofdplyr
anddata.table
that implement programmable NSE withoshka::expand
.
Installation
This package is proof-of-concept. If it elicits enough interest we will re-write the internals in C and add helper functions for common use patterns.
install.packages('oshka')
# or development version
devtools::instal_github('brodieg/oshka@development')
Feedback is welcome, particularly if you are aware of some NSE pitfalls we may be ignoring.
Acknowledgements
- R Core for developing and maintaining such a wonderful language.
- CRAN maintainers, for patiently shepherding packages onto CRAN and maintaining the repository, and Uwe Ligges in particular for maintaining Winbuilder.
- Lionel Henry for his early feedback on this project.
- Jim Hester because covr rocks.
- Dirk Eddelbuettel and Carl Boettiger for the rocker project, and Gábor Csárdi and the R-consortium for Rhub, without which testing bugs on R-devel and other platforms would be a nightmare.
- Hadley Wickham for devtools and roxygen2.
- Yihui Xie for knitr and J.J. Allaire etal for rmarkdown, and by extension John MacFarlane for pandoc.
About
Brodie Gaslam is a hobbyist programmer based on the US East Coast.
The name of this package is derived from "matryoshka", the Russian nesting dolls.