相同的函数,但使用名称 %>% 会导致与使用名称 := 时不同的结果

GKi*_*GKi 4 r pipe operator-precedence

我正在使用@Konrad Rudolph的函数,但将其名称从 更改%>%:=,并获得相同的调用不同的结果。

`%>%` = function (lhs, rhs) {
  subst = call('substitute', substitute(rhs), list(. = lhs))
  eval.parent(eval(subst))
}

`:=` <- `%>%`

1 %>% .+2 %>% .*3
#[1] 7

1 := .+2 := .*3
#[1] 3
Run Code Online (Sandbox Code Playgroud)

或者具有不同的功能。

`%>%` <- function(lhs, rhs) {
  assign(".", lhs, envir=parent.frame())
  eval(substitute(rhs), parent.frame())
}

`:=` <- `%>%`

1 %>% .+2 %>% .*3
#[1] 7

1 := .+2 := .*3
#[1] 9
Run Code Online (Sandbox Code Playgroud)

为什么使用名为 的函数时会得到其他结果:=

MrF*_*ick 7

原因是运算符优先级。我们可以使用该lobstr包来查看代码的抽象语法树。

\n
lobstr::ast(1 %>% .+1 %>% .+2)\n\xe2\x96\x88\xe2\x94\x80`+` \n\xe2\x94\x9c\xe2\x94\x80\xe2\x96\x88\xe2\x94\x80`+` \n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80\xe2\x96\x88\xe2\x94\x80`%>%` \n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x801 \n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80. \n\xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x96\x88\xe2\x94\x80`%>%` \n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x801 \n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80. \n\xe2\x94\x94\xe2\x94\x802 \n
Run Code Online (Sandbox Code Playgroud)\n

\n
lobstr::ast(1 := .+1 := .+2)\n\xe2\x96\x88\xe2\x94\x80`:=` \n\xe2\x94\x9c\xe2\x94\x801 \n\xe2\x94\x94\xe2\x94\x80\xe2\x96\x88\xe2\x94\x80`:=` \n  \xe2\x94\x9c\xe2\x94\x80\xe2\x96\x88\xe2\x94\x80`+` \n  \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80. \n  \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x801 \n  \xe2\x94\x94\xe2\x94\x80\xe2\x96\x88\xe2\x94\x80`+` \n    \xe2\x94\x9c\xe2\x94\x80. \n    \xe2\x94\x94\xe2\x94\x802 \n
Run Code Online (Sandbox Code Playgroud)\n

因此,当您运行该%>%版本时,管道在添加之前发生,但对于该:=版本,添加发生在添加之前:=

\n

如果添加隐式括号,您会发现这两个是等价的

\n
1 %>% .+1 %>% .+2\n((1 %>% .)+(1 %>% .))+2\n
Run Code Online (Sandbox Code Playgroud)\n

然而你可能期望的行为需要看起来像

\n
1 %>% (.+1) %>% (.+2)\n
Run Code Online (Sandbox Code Playgroud)\n

但仍然“有效”。这就是另一个表达式的分解方式

\n
1 := .+1 := .+2\n1 := ((.+1) := (.+2))\n(1+1) := (1+2)\n
Run Code Online (Sandbox Code Playgroud)\n

按照函数的定义方式,中间项基本上消失了,因为 被.外部项取代,因此内部项:=没有留下自由变量.=

\n

操作顺序在?Syntax帮助页面上定义。如果不更改 R 源代码本身,则无法更改函数的优先级。虽然没有在页面上明确列出,:=但具有相同的优先级<-(它在解析器中别名为 LEFT_ASSIGN)。

\n