在R语言中,函数的运算符重载——奇怪的行为

8

不幸的是,在 R 中,像 (f+g)(3) 这样同时有两个一元函数 f 和 g 的情况无法实现。因此,我尝试通过以下方式对一元函数重载 "+" 运算符:

"+.function" = function(e1, e2){
  return(function(x) e1(x) + e2(x))
}

但是如果我尝试使用这个,它什么也不做。代码如下:

 a = function(x) 2*x
 (a+a)(2)

如果+.function未被定义,将会产生与根本未定义相同的错误。

通过玩弄一段时间,我发现实际上有一种方法可以这样添加函数:如果这些函数是引用类的成员函数,则可以。也就是说,下面的代码(连同上面的“+”定义):

clsA = setRefClass("clsA", 
  methods = list(
    b = function(x) 2*x
  ))

inst_a = clsA$new()
(inst_a$b + inst_a$b)(2)

返回值为“8”(正如预期)。因此,我已经有了某种解决问题的方法。现在我的问题是:

这种奇怪行为的原因是什么?为什么+.function不关心“常规”函数而关心类成员函数?有人知道如何将该运算符扩展到常规函数吗?


如果您重新定义a的类别,例如像class(a)<-"test",并将您的“+.function”命名为“+.test”,那么(a+a)(2)就可以起作用。因此,函数class似乎是特殊的。 - Jouni Helske
不错,这个可行 :-) 嗯,虽然这仍然可以被视为一种解决方法,但我认为这比我的参考类想法更加“聪明”。非常感谢您提供的这个想法! - Patrick Roocks
2个回答

5
如果你重新定义了a的类,例如像这样:class(a)<-"ownfunction"(或者更好的是class(a)<-c("ownfunction","function")),并将你的"+.function"改为"+.ownfunction",那么(a+a)(2)就可以正常工作了。 似乎function类以某种特殊的方式进行处理:如果你运行debug("+.function");(a+a)(2),你会发现甚至没有调用"+.function" 编辑:请参见评论。

@Patrick 这是真的。我相信这是因为在 class(a) <- "function" 之后,a 具有了类属性 "function",而普通函数则不是这种情况。然而,在两种情况下,class(a) 都返回 "function" - QkuCeHBH
不错,所以即使“class”函数将“function”作为函数类,它实际上并不是“function”类的成员 :) - Jouni Helske
3
关于这个解决方案的另一个注释:为了允许像(f+g+h)(2)这样的表达式,应该使用 { res = function(x) e1(x) + e2(x); class(res) = "function"; return(res) }。另外:使用 ... 而不是 x 也可以支持n元函数,例如 (u+v)(2,2)。将 + 替换为 Ops.Primitive(.Generic) 也可以将解决方案推广到其他情况。 - Patrick Roocks
2
发生这种情况的原因是 is.object(function() {})FALSE,所以内部 S3 分派不会发生。这是一种性能优化,可以避免在使用基本类型时进行方法分派的开销。 - hadley
2
@JoshO'Brien OBJECT位集的基本类型之一都没有。你必须添加一个类属性,或使用S4对象。 - hadley
显示剩余3条评论

3

作为一种解决方法,您可以定义一个特殊运算符(%...%),如下所示:

,您可以定义一个 特殊运算符%...%)。

"%+%" <- function(e1, e2) {
  return(function(x) e1(x) + e2(x))
}

a <- function(x) 2*x
(a %+% a)(2) # == 8

这对我来说产生了与“+.函数”方法相同的错误。 - Jouni Helske
抱歉,忘记用“%+%”替换“+”了...现在应该可以工作了。 - QkuCeHBH
谢谢,一开始感觉有点奇怪,不过我误解了 %+% 的意思。 - Jouni Helske
这个确实可行;但是%+%看起来不太聪明。而且将其推广到-,,/等会产生很多代码行。通过上述思路,也可以实现Ops.function,将此运算符推广到+,-,等等... - Patrick Roocks
@Patrick 是的,我同意。然而,即使是标准的 R 也会使用 %...% 函数(例如,用于矩阵乘法的 %*% 或用于整数除法的 %/%)。 - QkuCeHBH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接