用于编写函数的rlang运算符的解释
Explanation of rlang operators used to write functions
我最近发布了两个与我尝试编写的函数相关的问题 (, )。我收到了每个有用的答案,这导致了以下两个功能:
second_table <- function(dat, variable1, variable2){
dat %>%
tabyl({{variable1}}, {{variable2}}, show_na = FALSE) %>%
adorn_percentages("row") %>%
adorn_pct_formatting(digits = 1) %>%
adorn_ns()
}
和
second_table2 = function(dat, variable1, variable2){
variable1 <- sym(variable1)
dat %>%
tabyl(!!variable1, {{variable2}}, show_na = FALSE) %>%
adorn_percentages("row") %>%
adorn_pct_formatting(digits = 1) %>%
adorn_ns()
}
这些函数按预期工作,但我以前从未使用过 rlang 包,仍然对 {{}} 运算符和 !! 之间的区别感到困惑。 + sym() 在查看可用文档并编写一些附加函数之后。我不喜欢使用我不完全理解的代码,并且相信我将来会进一步使用这些 rlang 运算符,因此非常感谢对这些运算符之间的区别进行简单的语言解释。
R 有一个称为非标准求值 (NSE) 的特殊功能,其中表达式按原样使用而不是被求值。大多数人在加载包时首先遇到 NSE:
a <- "rlang"
print(a) # Standard evaluation - the expression a is evaluated to its value
# [1] "rlang"
library(a) # Non-standard evaluation - the expression a is used as-is
# Error in library(a) : there is no package called ‘a’
rlang
通过提供三个主要函数来捕获未计算的符号和表达式来启用复杂的 NSE:
sym("x")
捕获一个符号(即变量名、列名等)。旧版本允许 sym(x)
,但我认为最新版本 rlang
强制输入为字符串。
expr(a + b)
捕获任意表达式
quo(a + b)
捕获任意表达式和定义这些表达式的环境。
expr
essions 和 quo
sures 之间的区别在于,前者的评估将在直接环境中完成,而后者始终在捕获表达式的环境中进行评估:
f <- function(e) {a <- 2; b <- 3; eval_tidy(e)}
a <- 5; b <- 10
f(expr(a+b)) # Evaluated inside f
# [1] 5
f(quo(a+b)) # Evaluated in the environment where it is captured
# [1] 15
所有三个动词都有 en
等价物:ensym
、enexpr
和 enquo
。这些用于捕获从函数内部提供给函数的符号和表达式。当您想要消除函数用户自己使用 sym
等的需要时,这很有用:
f <- function(x) {enexpr(x)} # Expression captured within a function
f(a+b)
# This has exact equivalence to
f <- function(x) {x}
f(expr(a+b)) # The user has to do the capture themselves
在所有情况下,运算符 !!
都会计算符号和表达式。将其视为类固醇的 eval()
,因为 !!
强制立即评估优先于其他所有内容。除其他事项外,这对于更复杂表达式的迭代构造很有用:
a <- expr(b + 2)
expr(d * !!a) # a is evaluated immediately
# d * (b + 2)
expr(d * eval(a)) # evaluation of a is delayed
# d * eval(a)
综上所述,{{x}}
是 !!enquo(x)
的 shorthand 表示法
我最近发布了两个与我尝试编写的函数相关的问题 (
second_table <- function(dat, variable1, variable2){
dat %>%
tabyl({{variable1}}, {{variable2}}, show_na = FALSE) %>%
adorn_percentages("row") %>%
adorn_pct_formatting(digits = 1) %>%
adorn_ns()
}
和
second_table2 = function(dat, variable1, variable2){
variable1 <- sym(variable1)
dat %>%
tabyl(!!variable1, {{variable2}}, show_na = FALSE) %>%
adorn_percentages("row") %>%
adorn_pct_formatting(digits = 1) %>%
adorn_ns()
}
这些函数按预期工作,但我以前从未使用过 rlang 包,仍然对 {{}} 运算符和 !! 之间的区别感到困惑。 + sym() 在查看可用文档并编写一些附加函数之后。我不喜欢使用我不完全理解的代码,并且相信我将来会进一步使用这些 rlang 运算符,因此非常感谢对这些运算符之间的区别进行简单的语言解释。
R 有一个称为非标准求值 (NSE) 的特殊功能,其中表达式按原样使用而不是被求值。大多数人在加载包时首先遇到 NSE:
a <- "rlang"
print(a) # Standard evaluation - the expression a is evaluated to its value
# [1] "rlang"
library(a) # Non-standard evaluation - the expression a is used as-is
# Error in library(a) : there is no package called ‘a’
rlang
通过提供三个主要函数来捕获未计算的符号和表达式来启用复杂的 NSE:
sym("x")
捕获一个符号(即变量名、列名等)。旧版本允许sym(x)
,但我认为最新版本rlang
强制输入为字符串。expr(a + b)
捕获任意表达式quo(a + b)
捕获任意表达式和定义这些表达式的环境。
expr
essions 和 quo
sures 之间的区别在于,前者的评估将在直接环境中完成,而后者始终在捕获表达式的环境中进行评估:
f <- function(e) {a <- 2; b <- 3; eval_tidy(e)}
a <- 5; b <- 10
f(expr(a+b)) # Evaluated inside f
# [1] 5
f(quo(a+b)) # Evaluated in the environment where it is captured
# [1] 15
所有三个动词都有 en
等价物:ensym
、enexpr
和 enquo
。这些用于捕获从函数内部提供给函数的符号和表达式。当您想要消除函数用户自己使用 sym
等的需要时,这很有用:
f <- function(x) {enexpr(x)} # Expression captured within a function
f(a+b)
# This has exact equivalence to
f <- function(x) {x}
f(expr(a+b)) # The user has to do the capture themselves
在所有情况下,运算符 !!
都会计算符号和表达式。将其视为类固醇的 eval()
,因为 !!
强制立即评估优先于其他所有内容。除其他事项外,这对于更复杂表达式的迭代构造很有用:
a <- expr(b + 2)
expr(d * !!a) # a is evaluated immediately
# d * (b + 2)
expr(d * eval(a)) # evaluation of a is delayed
# d * eval(a)
综上所述,{{x}}
是 !!enquo(x)