问题
I´m working on a R package that takes strings as function arguments. Now I want to use non-standard evaluation to allow for non-string input. Also, to keep the backwards compatibility, I´d like to keep the possibility for the functions to take strings.
Hadley gives an example with the subset function and suggests that every NES function should be accompanied by a standard evaluation function.
library(lazyeval)
# standard evaluation
subset2_ <- function(df, condition) {
r <- lazy_eval(condition, df)
r <- r & !is.na(r)
df[r, , drop = FALSE]
}
subset2_(mtcars, lazy(mpg > 31))
# NES can be written easily afterwards
subset2 <- function(df, condition) {
subset2_(df, lazy(condition))
}
While the SE function now also takes quoted input,
subset2_(mtcars, "mpg > 31")
the NSE function throws an error:
subset2(mtcars, "mpg > 31")
But I want the user to have the same function (the NSE function) for both quoted as well as unquoted arguments.
Any ideas?
回答1:
The NSE function takes NSE input. That’s the point of this pattern, isn’t it?
subset2(mtcars, mpg > 31)
You can of course allow the NSE function to take character input as well but I’d advise against this — strongly. Don’t mix SE and NSE, there’s no advantage to be had, and it sows confusion (and potentially bugs, since you’re mixing domains).
That said, the following of course works:
subset2 <- function(df, condition) {
if (is.character(substitute(condition)))
subset2_(df, condition)
else
subset2_(df, lazy(condition))
}
If you want to allow NSE and SE in the same function for backwards compatibility reasons, I suggest phasing out the SE version in a future version, and adding a deprecation warning for now. To add the deprecation warning:
subset2 <- function(df, condition) {
if (is.character(substitute(condition))) {
msg = sprintf(paste0('Calling %s with a quoted expression is',
' deprecated. Pass an unquoted expression',
' instead, or use %s.'),
sQuote('subset2'), sQuote('subset2_'))
.Deprecated(msg = msg)
subset2_(df, condition)
}
else
subset2_(df, lazy(condition))
}
来源:https://stackoverflow.com/questions/33214278/how-to-write-an-nes-function-that-also-takes-character-input