2014-11-21 54 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