S4 setMethod的R可选参数

时间:2014-11-21 18:21:20

标签: r oop s4

我有兴趣为通用功能设置新方法。例如,我们说我有一个新课程(例如coolClass)。我可以编写一个包装器来计算该类的log10,并使用以下代码轻松设置该方法:

setMethod("Math", c(x="coolClass"),
          function(x)
          {
            op = .Generic[[1]]
            switch(op,
                   `log10` = log10_for_coolClass(x),
                   stop("Undefined operation")
            )
          }
)

但是,我无法弄清楚如何设置传递多个参数的方法。例如,通用log方法。正在运行getGeneric("log")会显示以下内容:

> getGeneric("log")
standardGeneric for "log" defined from package "base"
  belonging to group(s): Math 

function (x, ...) 
standardGeneric("log", .Primitive("log"))
<bytecode: 0x2f9a958>
<environment: 0x2f937f0>
Methods may be defined for arguments: x
Use  showMethods("log")  for currently available ones.

看到这个,我希望我可以编写以下代码来传递可选的base参数。

setMethod("Math", signature(x="coolClass",...),
          function(x, ...)
          {
            op = .Generic[[1]]
            switch(op,
                   `log` = log_for_coolClass(x, ...),
                   stop("Undefined operation")
            )
          }
)

但是我收到以下错误:

Error in matchSignature(signature, fdef, where) : 
  '...' used in an incorrect context

...中没有signature的情况下尝试我收到了不同的错误:

Error in rematchDefinition(definition, fdef, mnames, fnames, signature) : 
   methods can add arguments to the generic ‘Math’ only if '...' is an argument to the generic

鉴于getGeneric日志显示方法中的...,这对我来说似乎很奇怪。

有什么想法吗?有没有办法捕获其他参数?我试图使用S4方法更舒服,但我对如何传递可选参数感到困惑。如果这是不可能的,如果有人可以解释log函数如何工作,我将不胜感激,例如,假设该函数是Math组的一部分但接受多个参数。

更新

奇怪的是,如下所述,我可以直接在setMethod上使用log,内容如下:

setMethod("log", signature(x="big.matrix"),
          function(x, base=exp(1))
            {
            log_for_coolClass(x, base=base)
          }
          )

但是,这并不能平息我的好奇心。例如,如果我在Math组中创建了许多新方法,那么在代码中如此重复似乎很奇怪。理想情况下,它看起来像这样:

setMethod("Math", c(x="coolClass"),
          function(x, base=exp(1))
          {
            op = .Generic[[1]]
            switch(op,
                   `log10` = log10_for_coolClass(x),
                   `log` = log_for_coolClass(x, base=base),
                   stop("Undefined operation")
            )
          }
)

1 个答案:

答案 0 :(得分:1)

这是一个班级

.A <- setClass("A", representation(x="numeric"))

对于像log这样的函数,我们有

> getGeneric("log")
standardGeneric for "log" defined from package "base"
  belonging to group(s): Math 

function (x, ...) 
standardGeneric("log", .Primitive("log"))
<bytecode: 0x2b41b28>
<environment: 0x2b39df8>
Methods may be defined for arguments: x
Use  showMethods("log")  for currently available ones.

签名包含...。所以我们写了

setMethod("log", "A", function(x, ...) {
    log(x@x, ...)
})

并取得成功

> log(.A(x=c(1, 2, NA)))
[1] 0.0000000 0.6931472        NA
> log(.A(x=c(1, 2, NA)), base=2)
[1]  0  1 NA

接下来:log10

> getGeneric("log10")
standardGeneric for "log10" defined from package "base"
  belonging to group(s): Math 

function (x) 
standardGeneric("log10", .Primitive("log10"))
<bytecode: 0x2b4a700>
<environment: 0x2b43138>
Methods may be defined for arguments: x
Use  showMethods("log10")  for currently available ones.

泛型中没有...个参数,所以我们基本上卡住了 - 编写我们自己的泛型和实现包含...的方法,或者写一个没有的log10,A方法...论证。

关于...的相同原则适用于组泛型 - 数学组泛型没有点

> getGeneric("Math")
groupGenericFunction for "Math" defined from package "base"

function (x) 
standardGeneric("Math")
<bytecode: 0x2771d40>
<environment: 0x275ee20>
Methods may be defined for arguments: x
Use  showMethods("Math")  for currently available ones.

所以我们的方法(实现所有数学运算,而不仅仅是日志;注意我们通常不会明确地引用.Generic)可能是

setMethod("Math", "A", function(x) {
    callGeneric(x@x)
})

现在我们有了所有数学函数的方法,例如

> sqrt(.A(x=1:4))
[1] 1.000000 1.414214 1.732051 2.000000

另外,我们的log变种,接受......仍然可用,因此我们既可以为所有Math泛型定义类的行为,也可以为特定泛型提供专门的实现。

可能需要解决这些群组泛型的实现中的错误。如果在新会话中我们定义了我们的类和Math泛型,而不是log函数和...参数,我们仍然可以调用

> log(.A(x=1:4))
[1] 0.0000000 0.6931472 1.0986123 1.3862944
> log(.A(x=1:4), base=2)
[1] 0.0000000 0.6931472 1.0986123 1.3862944

其中第二个参数被忽略,但确实应该导致错误。