2014-11-21 2 views
3

Мне интересно установить новые методы для общих функций. Например, допустим, у меня есть новый класс (например, coolClass). Я мог бы написать обертку, чтобы вычислить log10 этого класса и легко установить метод со следующим кодом:R дополнительных аргументов для S4 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, но принимает несколько аргументов.

Update

Любопытно, что, как указано ниже, можно использовать 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

Вот класс

.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 

Далее: 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([email protected]) 
}) 

и теперь у нас есть методы для всех математических функций, например,

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

также наш вариант журнала, принимающий ..., по-прежнему доступен, поэтому мы можем определить поведение нашего класса для всех математических приемов 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 

где второй аргумент игнорируется, но должны действительно привести к ошибке.

+0

Ваш ответ пришел так же, как я обнаружил 'setMethod' непосредственно на' log'. Интересно получить доступ ко всем операциям Math с помощью 'callGeneric', но мой класс требует более сложных функций, которые я пишу отдельно и должен вызывать. Таким образом, кажется, что я должен установить определенные методы отдельно. Я надеялся быть более кратким (см. Обновленный вопрос), но если это единственный способ. – cdeterman

Смежные вопросы