是否可以在没有%%的情况下定义运算符?

问题描述 投票:10回答:2

在R中允许用户定义的运算符,但似乎只接受% %之类的运算符。是否有可能绕过这个限制来定义运算符,例如>>,或者不像% %的东西?

运算符必须是真正的运算符,以便我们可以像1 >> 2一样使用它,而不必像">>"(1,2)那样使用它。

r operator-keyword
2个回答
17
投票

不,R只允许你

  1. 重新定义现有的运算符(例如`+`或者`<-`)和
  2. 通过用%…%包围它们来定义新的中缀运算符。

这些是我们必须遵守的规则。但是,在这些规则中,一切都是公平的。例如,我们可以为字符串重新定义`+`以执行连接,而不会破坏其正常含义(添加):

`+`
# function (e1, e2)  .Primitive("+")

这是旧的定义,我们希望为数字保留:

`+.default` = .Primitive('+')
`+.character` = paste0`1
`+` = function (e1, e2) UseMethod('+')
1 + 2
# [1] 3
'hello' + 'world'
# [1] "helloworld"

这利用了R中的S3类系统,使`+`在其第一个参数的类型上完全通用。

因此可以重新定义的运算符列表非常折衷。首先,它包含以下运算符:

+-*/^&|::::::$=<-<<-==<<=>>=!=~&&||!?@:=({[[[

(来自{modules} source code。)

在此列表中,一个特定的运算符值得注意:`:=`是一个可覆盖的运算符(例如{data.table}使用它)但与此列表中的大多数其他运算符不同,它没有默认实现。

同样,您可以定义几乎所有运算符的赋值版本,而不仅仅是具有预定义赋值的赋值版本(例如`[<-`)。例如,`(<-``{<-`也缺少默认实现。这就是以下代码失败的原因:

a = 1
(a) = 2
# Error in (a) = 2 : could not find function "(<-"
{a} = 3
# Error in { : could not find function "{<-"

但是可以通过定义运算符使代码工作:

`(<-` = `{<-` = function (x, value) value

每个函数都有相同的功能,包括几乎所有的运算符1,甚至是控制结构(参见本答案下面的注释)。

相比之下,`**`不是真正的算子:它是`^`的语法别名。用户可以定义自己的`**`函数,但不能通过代码a ** b调用它,因此它不是一个可覆盖的运算符(除了通过重写`^`)。

同样,您可以通过重新定义->来覆盖<-(仅限)。这似乎很少有意义 - 但至少有一个很好的例子,定义较少冗长的lambda:

> sapply(1 : 4, x -> 2 * x)
[1] 2 4 6 8

Implementation as a gist


1唯一的例外是赋值运算符:由于语言的a <- b <- c,你不能通过重新定义`<-<-`(和`=<-``<<-``:=`相同)来改变operator precedence and associativity rules的含义。但是,以下代码调用`(<-``<-<-`,如果未定义其中任何一个,则会失败:

(a <- b) <- c

弄乱。


4
投票

您可以执行此类操作,但您可能希望将这些对象分配给新环境以确保安全。

> "^" <- function(x, y) `-`(x, y)  ## subtract y from x
> 5 ^ 3
# [1] 2

> "?" <- function(x, y) sum(x, y)  ## add x and y
> 5 ? 5
# [1] 10
© www.soinside.com 2019 - 2024. All rights reserved.