如何编写也需要字符输入的NES函数?

时间:2015-10-19 12:22:17

标签: r eval lazy-evaluation

我正在研究一个将字符串作为函数参数的R包。现在我想使用非标准评估来允许非字符串输入。另外,为了保持向后兼容性,我希望保留函数接受字符串的可能性。

Hadley给出example子集函数,并建议每个NES函数都应附带标准评估函数。

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))
}

虽然SE功能现在也需要引用输入,

subset2_(mtcars, "mpg > 31")

NSE函数抛出错误:

subset2(mtcars, "mpg > 31")

但我希望用户对引用和不引用的参数都有相同的功能(NSE功能)。

有什么想法吗?

1 个答案:

答案 0 :(得分:4)

NSE功能需要 NSE 输入。这就是这种模式的重点,不是吗?

subset2(mtcars, mpg > 31)

你当然可以允许NSE功能进行字符输入,但我强烈建议不要这样做。不要混合使用SE和NSE,没有任何优势,它会产生混乱(并且可能存在错误,因为您正在混合域名。)

那说,以下当然有效:

subset2 <- function(df, condition) {
    if (is.character(substitute(condition)))
        subset2_(df, condition)
    else
        subset2_(df, lazy(condition))
}

如果出于向后兼容性的原因,您希望在同一功能中允许NSE和SE,我建议在将来的版本中逐步淘汰SE版本,并立即添加弃用警告。要添加弃用警告:

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))
}