2

Advanced R的第 19 章解释了expr()在函数内部没有用处。

但是,在以下情况下,如果没有expr().

假设我想在一个函数中对一个 tibble 进行分组。

data(iris)
iris %>% group_by(Species)

显而易见的方法是使用“卷曲卷曲”。

func_a <- function(data, grouping) {
  data %>% group_by({{grouping}})
}
func_a(iris, Species)

但是,如果我允许任意提供的表达式,则“卷曲”不起作用。

func_b <- function(data, ...) {
  data %>% group_by({{...}})
}
func_b(iris, Species)
# Error in (function (x)  : object 'Species' not found

最后,我发现我需要expr()让它工作。

func_c <- function(data, ...) {
  grouping <- expr(...)
  data %>% group_by(!!grouping)
}
func_c(iris, Species)

expr()Advanced R 中的示例是:

f1 <- function(x) expr(x)
f1(a + b + c)
#> x

我的主要问题是为什么func_c有效。是否expr()...原样评估它!!?为什么我们要采取不同的方法...呢?

然后,我不确定为什么这不起作用。

func_d <- function(data, grouping) {
  grouping <- expr(grouping)
  data %>% group_by(!!grouping)
}
func_d(iris, Species)

我还检查了rlang manual,但解释对我来说太简短了。

4

2 回答 2

2

expr防止对代码进行评估。例如,除非是您之前声明的变量,否则尝试x自行运行将失败- R 将在您评估它时寻找其中的值,如果没有找到这样的值,则会发出错误。相反,将永远不会失败(即使尚未声明),因为它告诉 R“从表面上看,不要去寻找它可能代表的其他东西”。将返回“名称”类型的东西,基本上就是 - 一个名称。您可以将名称视为您和 R 之间的接口——它是您输入的内容,以及您传达指令的方式。和刚才做的一样。xxexpr(x)xexprexpr(x)eval(expr(x))x

现在按顺序列出您的示例:

func_c <- function(data, ...) {
  grouping <- expr(...)
  data %>% group_by(!!grouping)
}
func_c(iris, Species)

这是有效的,因为Species将直接通过 传递给expr...并且返回类型将是一个“名称”,它存储在变量中grouping。可以使用!!as you did it 或 with评估名称eval。无论哪种方式,doing!!grouping都会导致 R 首先去寻找grouping变量代表什么,找到Species. 变量被它的值替换,最后!!Species会告诉 R 去寻找名为 Species 的变量,在group_by函数的上下文中,它会给你一个名为“Species”的列。

继续您的下一个示例:

f1 <- function(x) expr(x)
f1(a + b + c)

这不能仅仅因为expr(x)阻止任何评估而起作用。R 不会去寻找里面的东西x,所以它永远不会找到a + b + c,它采用x表面价值,这就是你得到的。

最后,我们有你的最后一个例子:

func_d <- function(data, grouping) {
  grouping <- expr(grouping)
  data %>% group_by(!!grouping)
}
func_d(iris, Species)

这与您的第一个示例类似,但这里有一个额外的变量 - 名为grouping. 在您的第一个示例中,Species直接(通过)输入函数...,因此它没有绑定到任何参数名称。在这第三个示例中,Species通过命名参数进入函数,即绑定到变量grouping。但是,expr(grouping)告诉 R “不要费心寻找grouping代表什么,我这里有我需要的一切”......所以它根本找不到Speciesexpr(grouping)只是给你 name grouping,不管变量本身是什么。因此,当您尝试使用!!groupingwithin进行评估时group_by,R 会尝试查找名为grouping... 的列名,不用说,它没有找到它,您会得到一个Column grouping is not found错误。

于 2020-07-06T02:02:56.147 回答
0

将其视为expr()!!有效地相互否定。

func_c <- function(data, ...) {
  grouping <- expr(...)
  data %>% group_by(!!grouping)
}

相当于

func_c <- function(data, ...) {
  data %>% group_by(...)            # Proper way to handle dots, by the way
}

(这不是完全等价的,因为前一种实现在 中扩展点expr,而后者在 中扩展点group_by。但是当向 提供单列符号时,两种实现都会产生相同的输出...。)

同样地,

func_d <- function(data, grouping) {
  grouping <- expr(grouping)
  data %>% group_by(!!grouping)
}

相当于

func_d <- function(data, grouping) {
  data %>% group_by(grouping)         # No column `grouping` in iris
}

要开始func_d工作,您需要替换expr()enexpr(). 这将捕获提供给函数的表达式,而不是表达式grouping本身。

于 2020-07-06T04:44:58.197 回答