R:在非标准评估(NSE)中,使用magrittr时如何确定正确的调用环境?'parent.frame()' 不起作用



考虑

proper_filter <- function(.data, ...) {
code = substitute(filter(.data, ...))
print(names(parent.frame()))
}
fn_wo_magrittr <- function(dfr, val) {
proper_filter(dfr, speed < val) 
}
fn_w_magrittr <- function(dfr, val) {
dfr %>% 
proper_filter(speed < val) 
}
val2 = 10
fn_wo_magrittr(cars, val2)
fn_w_magrittr(cars, val2)

当调用proper_filter时,函数只打印在parent.frame()中定义的名称。

fn_wo_magrittr不使用{magrittr},因此它标识了定义了dfrval的右侧parent.frame()

但是函数fn_wo_magrittr使用{magrittr},因此parent.frame()不是直接的调用环境,而是可能被%>%更改。

如何找到合适的通话环境?调用%>%的那个。我似乎想不通。

您试图做的事情可能不安全。据我所知,magrittr并没有记录它运行时堆栈帧的样子,所以虽然你可能会让它工作,但它不一定会在下一个magrittr版本中继续工作。

相反,您应该使用R管道|>。它记录为进行非常简单的语法操作,因此

dfr |>
proper_filter(speed < val) 

被记录为与相同

proper_filter(dfr, speed < val)

R管道有几个缺点:它只在R 4.1.0或更新版本中可用,而且它更受限制,例如.不支持作为占位符,所以也许你最好的方法是根本不使用管道。

1(显式传递环境通常,将环境传递给使用环境的函数更安全、更灵活。仍然可以使用parent.frame()作为默认值,但使用显式参数可以处理一般情况。

library(magrittr)
val2 <- 10
proper_filter2 <- function(.data, ..., envir = parent.frame()) {
code <- substitute(filter(.data, ...))
print(ls(envir))
}
fn_w_magrittr2 <- function(dfr, val, .envir = environment()) {
dfr %>% 
proper_filter2(speed < val, envir = .envir)
}
fn_w_magrittr2(cars, val2)
## [1] "dfr"   "val"  

2(公式另一种处理方法是使用公式,因为它们有环境。proper_filter3的公式参数应该是单侧公式。

library(magrittr)
val2 <- 10
proper_filter3 <- function(.data, formula) {
code <- substitute(filter(.data, rhs), list(rhs = formula[[2]]))
print(ls(environment(formula)))
}
fn_w_magrittr3 <- function(dfr, val) {
.formula <- ~ speed < val
dfr %>% 
proper_filter3(.formula)
}
fn_w_magrittr3(cars, val2)
## [1] "dfr"     "val"   

3(pipe_ager_lexicalmagrittr包包含一个pipe_ageer_lexical,它当前未分配给中缀管道符号。它将在magrittr的下一个版本中定义,如本次提交所示,但与此同时,我们可以自己将其分配给中缀符号。

# as in question
proper_filter <- function(.data, ...) {
code = substitute(filter(.data, ...))
print(names(parent.frame()))
}
`%!>%` <- magrittr::pipe_eager_lexical   # <------- note this definition
fn_w_magrittr4 <- function(dfr, val) {
dfr %!>% 
proper_filter(speed < val) 
}
val2 <- 10
fn_w_magrittr4(cars, val2)
## [1] "."   "dfr" "val"

中的magrittr问题中对此进行了一些讨论https://github.com/tidyverse/magrittr/issues/171,https://github.com/tidyverse/magrittr/issues/38和https://github.com/tidyverse/magrittr/issues/70他们似乎得出结论,如果不牺牲magrittr的重要特征,就无法在magrittr内部以一般的方式解决这一问题,尽管magrittr热切的词汇管道就足够了。

上面展示了如何在仍然使用magrittr的情况下处理此问题,但替换magrittr也有可能。另一个答案提到|>,Bizarro管道可以用于另一种解决方案,当然,不使用管道总是有可能的。

最新更新