class 的 expr 和 exprs 在 R 的 rlang 中是不同的!为什么?

class of expr and exprs are different in rlang in R ! Why?

我不确定这里是否有人问过这个问题,但我在这里很困惑。我正在阅读 Hadley Wickham 的这本很棒的书 Advanced R,来自 here

这里描述了一个名为 cement 的函数,我对其进行了一些修改并试图理解它。

library(rlang)
cement1 <- function(x) {
  dots <- expr(x)
  print(class(dots))
  #paste(expr_name(x))
}

cement2 <- function(y,z) {
  dots <- exprs(y,z)
  print(class(dots))
  #paste(purrr::map(dots, expr_name), collapse = " ")
}

运行 上面的 cement1 没有任何参数 return 我是 class 的点作为 "name".

然而,当我运行带有附加参数的cement2函数时,classreturns "list",{简单地说class(expr(x)) returns "name" 而 class(exprs(x)) returns "list"}。

我不明白为什么它打印的 class return 由 exprexprs 编辑。我认为我知道的唯一区别是,一个处理一个参数,另一个处理多个参数,但我可能错了,我可能错过了一些细节。

原始问题:因此,这一切都是从 运行 通过删除代码中 cement1cement2,当我 运行 函数时,下面是它们 returned 的输出:

cement1(Hello) #Returns , Error in type_of(.x) : object 'Hello' not found 
cement2(Hello) #Works very well and returns, [1] "y z"

所以我试图找出 cement1 失败的原因,然后打印出他们的 classes 然后我意识到,exprexprs return 不同 classes.

我的问题是:

1) 它们是设计使然吗?如果是,那为什么?或者,我正在犯一些我目前看不到的可怕错误。

2) 如果不行,cement1 是不是不行,正确的方法是什么?

很抱歉句子太长,我的第一语言不是英语,因此如果有任何愚蠢的地方,请告诉我我会改正。我希望这不是重复的,我试图找到答案但我自己找不到。

感谢您的帮助。

R 版本: 3.4.2 rlang: 0.2.0

1) 是的,exprexprs 的 return 值因设计而异。来自 ?expr 帮助页面:

enexpr() and expr() capture a single raw expression.

enexprs() and exprs() capture a list of raw expressions including expressions contained in ....

2) expr_name() 需要引用表达式,例如 expr() 生成的表达式。因此,您需要修改 cement1 以在 dots 上调用 expr_name(),而不是 x。您还可以删除 paste 因为您没有连接任何东西。

cement1 <- function(x) {
  dots <- expr(x)
  # print(class(dots))      ## Commented out for clarity
  expr_name(dots)           ## The input to expr_name is now effectively expr(x)
}
cement1( Hello )
# "x"

你的函数 cement2 基本上调用 expr_name()exprs() 编辑的列表 return 的每个元素,然后将结果连接成一个字符串。

2a) 现在我们让您的 cement1 正常工作,我们可以进一步改进它。目前,该函数不使用其输入参数 xexpr() 简单地捕获未计算的表达式,这个表达式将永远是 x,不管你给你的参数命名:

cement1.1 <- function( completelyIgnoredName ) {
  dots <- expr(x)
  expr_name(dots)
}
cement1.1( Hello )
# "x"

但是,如果将 expr() 替换为 enexpr(),该函数将 替换 作为函数参数提供的表达式并捕获 代替:

cement1.2 <- function(x) {
  dots <- enexpr(x)
  expr_name(dots)
}
cement1.2( Hello )
# "Hello"