奇怪的 dplyr+NSE:在 mutate 中的自定义函数中使用 NSE

Weird dplyr+NSE: using NSE in custom function inside mutate

我在 dplyr::mutate 内的自定义函数中使用 NSE 时偶然发现了一个问题。考虑以下代码:

require(tidyverse)

f <- function(var) {
  varname <- deparse(substitute(var))
  v1      <- as.name(sprintf("%s.Width", varname))
  v2      <- as.name(sprintf("%s.Length", varname))
  return(substitute(v1 + v2))
}

iris %>% 
  mutate(
    test = f(Sepal) %>% eval()
  )

ff <- function(var) {
  varname <- deparse(substitute(var))
  v1      <- as.name(sprintf("%s.Width", varname))
  v2      <- as.name(sprintf("%s.Length", varname))
  substitute(v1 + v2) %>% eval.parent(n = 1)
}

iris %>% 
  mutate(
    test = ff(Sepal)
  )

此处 f 工作正常,但需要外部调用 eval() 才能在 mutate() 环境中执行代码。 这当然有点难看并导致大量样板代码。我对这项工作的最佳猜测是 ff,它试图在其调用环境中评估构造的表达式——我希望它是 mutate() 环境。但是,这会抛出一个变量未找到的错误。 关于如何使这项工作以及根本问题是什么的任何想法?本质上我想在 dplyr 动词中允许自定义 'macros' 。

使用 !! 整洁求值 "unquote" 运算符:

ff <- function(var) {
  varname <- deparse(substitute(var))
  v1      <- as.name(sprintf("%s.Width", varname))
  v2      <- as.name(sprintf("%s.Length", varname))
  substitute(v1 + v2)
}

iris %>% 
  head() %>% 
  mutate(
    test = !! ff(Sepal)
  )