2014-11-21 50 views
3

我有兴趣为通用函数设置新方法。例如,假设我有一个新班级(例如coolClass)。我可以写一个包装来计算类的log10和方便的设置方法与下面的代码:用于S4的R可选参数setMethod

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组的一部分,但接受多个参数,我将不胜感激。

更新

奇怪的是,如下所述,我可以直接在log使用setMethod有以下几点:

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

这里的一类

.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([email protected], ...) 
}) 

,并有成功

> 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 

下一步:日志10个

> 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([email protected]) 
}) 

,现在我们必须为所有的数学函数方法,例如,

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

此外,我们的日志变种,接受...,仍然可用,所以我们都可以为所有数学泛型定义我们的类的行为,并为特定的泛型提供专门的实现。

这些组仿真的实现可能存在一个缺陷,应该加以解决。如果在一个新的会议上,我们与...参数定义了我们班和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 

其第二个参数被忽略,但确实应该引起错误。

+0

你的答案就像我直接在'log'上发现'setMethod'一样。使用'callGeneric'访问所有数学运算是很有趣的,但是我的类需要更复杂的函数,我需要单独编写并且必须调用。因此,看起来我必须分开设置某些方法。我希望能够更简洁(见更新的问题),但如果这是唯一的方法。 – cdeterman 2014-11-21 20:22:39