我有兴趣为通用功能设置新方法。例如,我们说我有一个新课程(例如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")
)
}
)
答案 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
其中第二个参数被忽略,但确实应该导致错误。