匿名函数中的rlang :: sym

时间:2018-08-17 20:26:34

标签: r rlang nse tidyeval

我最近注意到rlang::sym在匿名函数中似乎不起作用,我也不明白为什么。这里有一个例子,它很笨拙而且很丑陋,但我认为它说明了这一点

require(tidyverse)
data <- tibble(x1 = letters[1:3],
               x2 = letters[4:6],
               val = 1:3)

get_it <- function(a, b){
    data %>%
        mutate(y1 = !!rlang::sym(a)) %>%
        mutate(y2 = !!rlang::sym(b)) %>%
        select(y1, y2, val)
}
get_it("x1", "x2")

这定义了一些玩具数据和一个(可怕的)函数,该函数实质上根据列名重命名列。现在,我可以对a和b的不同组合执行相同的操作:

d <- tibble(x = c("x1", "x2"),
            y = c("x2", "x1"))
d %>% mutate(tmp = map2(x, y, get_it))

但是,如果我尝试使用匿名函数执行完全相同的操作,那将不起作用:

d %>% mutate(tmp = map2(x, y, function(a, b){
data %>%
    mutate(y1 = !!rlang::sym(a)) %>%
    mutate(y2 = !!rlang::sym(b)) %>%
    select(y1, y2, val)
}))

即使object 'a' not found的功能完全相同(此处只是匿名),也会失败。谁能解释为什么?

1 个答案:

答案 0 :(得分:7)

请注意,以下代码在匿名函数中具有#NoTrayIcon #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. ; #Warn ; Enable warnings to assist with detecting common errors. SendMode Input ; Recommended for new scripts due to its superior speed and reliability. SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. SetWidth = 1616 SetHeight = 939 Run, ".\full throttle remastered.bat" Process, Wait, throttle.exe, 120 Process, Exist, throttle.exe Throttle = %ErrorLevel% if Throttle != 0 { Sleep, 2000 CenterWindow("ahk_exe throttle.exe") } else { MsgBox "Full Throttle Remastered could not be started" } return ; The following function centers the specified window on the screen if not already centered: CenterWindow(WinTitle) { WinGetPos,xx,yy, winx, winy, %WinTitle% x1 := xx + winx/2 y1 := yy + winy/2 loop 2 { y1 := yy + winy/2 loop 2 { if ((A_ScreenWidth/2 = x1) && (A_ScreenHeight/2 = y1) && (winx = %SetWidth%) && (winy = %SetHeight%)) { msgbox got em return } else y1 := y1 + 0.5 } x1 := x1 + 0.5 } WinMove, ahk_exe throttle.exe,, 0, 0, %SetWidth%, %SetHeight% WinGetPos,,, winx, winy, %WinTitle% Sleep, 100 WinMove, %WinTitle%,, (A_ScreenWidth/2)-(winx/2), (A_ScreenHeight/2)-(winy/2) } return ,并且可以正常工作:

rlang::sym()

原始问题与取消引用运算符map2(c("x1","x2"), c("x2","x1"), function(a, b){ data %>% mutate(y1 = !!rlang::sym(a)) %>% mutate(y2 = !!rlang::sym(b)) %>% select(y1, y2, val)}) 及其相对于非标准评估(NSE)函数(例如!!中的匿名函数创建的优先级)有关。考虑嵌套数据框

mutate

如果我尝试使用以下方法在每个内部数据框中选择第一列

XX <- data_frame( dfs = list(
  data_frame( x = letters[1:3], y = 1:3 ),
  data_frame( x = letters[4:6], y = 4:6 )) )

我收到一个XX %>% mutate( dfs1 = map( dfs, function(df) { i <- 1 df %>% select(!!i)} )) 错误,因为在创建匿名函数(包含object 'i' not found)的环境之前,!!的取消引用相对于外部mutate发生了。如果我将匿名函数移到select

之外
mutate

它可以正常工作,因为map( XX$dfs, function(df) { i <- 1 df %>% select(!!i)} ) 遵循标准的评估规则,并且现在在取消引用之前创建了匿名函数环境。


map的帮助页面指出

  

!!运算符取消引用其参数。它会在周围环境中立即得到评估。

这意味着当您在!!内编写复杂的NSE表达式时,例如select,取消引用将在整个表达式的环境中发生。正如@lionel在评论中指出的那样,NSE中的取消引用优先于其他事情,例如创建匿名函数环境。