Способ отправки при смешивании S3 и S4 - PullRequest
0 голосов
/ 04 ноября 2019

Я бы хотел понять, как проходит этап R, чтобы найти подходящую функцию при смешивании S3 и S4. Вот пример:

set.seed(1)
d <- data.frame(a=rep(c('a', 'b'), each=15),
                b=rep(c('x', 'y', 'z'), times=5),
                y=rnorm(30))

m <- lme4::lmer(y ~ b + (1|a), data=d)
l <- lsmeans::lsmeans(m, 'b')
multcomp::cld(l)

Я не до конца понимаю, что происходит, когда исполняется последняя строка.

multcomp::cld печатает UseMethod("cld"), поэтому отправка метода S3.

isS4(l) показывает, что l является объектом класса S4.

Кажется, что несмотря на вызов универсального S3, система диспетчеризации S3 полностью игнорируется. Создание функции print.lsmobj <- function(obj) print('S3') (так как class(l) равно lsmobj) и выполнение cld(l) не печатает "S3".

showMethods(lsmobj) или showMethods(ref.grid) (суперкласс), не перечислятьвсе, что напоминает функцию cld.

Использование debugonce(multcomp::cld) показывает, что функция, которая вызывается в конечном итоге, равна cld.ref.grid из lsmeans.

Однако мне было интересно, какПоймите, что cld.ref.grid будет в конечном итоге вызываться без каких-либо "уловок", таких как debugonce. То есть какие шаги R выполняет, чтобы добраться до cld.ref.grid.

Ответы [ 2 ]

1 голос
/ 08 ноября 2019

Более старая документация R (до 2016 года) содержала больше деталей, чем текущая документация, но, грубо говоря, процесс выглядит следующим образом в порядке убывания приоритета:

1), если функция является стандартнойУниверсальный S4 и любой из аргументов в сигнатуре - S4 (согласно isS4), тогда лучший метод S4 выбирается в соответствии с обычными правилами.

2) если функция является нестандартным универсальным S4, товыполняется его тело, которое в какой-то момент вызывает саму диспетчеризацию S4.

3) если функция является универсальной функцией S3, тогда диспетчеризация S3 выполняется по первому аргументу (за исключением внутренних универсальных бинарных операторов).

4) если функция вообще не является универсальной, то она оценивается обычным образом с ленивой оценкой для всех своих аргументов.

Обратите внимание, что со страницы справки setGeneric:

"Функции, которые отправляют методы S3 путем вызова UseMethod, являются обычными функциями, а не объектами из класса "genericFunction". Neric, как и любая другая функция, но некоторые специальные соображения применяются для обеспечения согласованности отправки методов S4 и S3 (см. Methods_for_S3). "

1 голос
/ 04 ноября 2019

Для регистрации методов S3 должен быть доступен общий тип. Здесь я пишу простой foo метод для merMod объектов:

> library(lme4)
> foo.merMod = function(object, ...) { "foo" }

> showMethods(class = "merMod")

Function ".DollarNames":
 <not an S4 generic function>

Function "complete":
 <not an S4 generic function>

Function "formals<-":
 <not an S4 generic function>

Function "functions":
 <not an S4 generic function>
Function: getL (package lme4)
x="merMod"

Function "prompt":
 <not an S4 generic function>
Function: show (package methods)
object="merMod"

> methods(class = "merMod")
 [1] anova          as.function    coef           confint        cooks.distance
 [6] deviance       df.residual    drop1          extractAIC     family        
[11] fitted         fixef          formula        getL           getME         
[16] hatvalues      influence      isGLMM         isLMM          isNLMM        
[21] isREML         logLik         model.frame    model.matrix   ngrps         
[26] nobs           plot           predict        print          profile       
[31] ranef          refit          refitML        rePCA          residuals     
[36] rstudent       show           sigma          simulate       summary       
[41] terms          update         VarCorr        vcov           weights              

Ни один из списков не включает foo. Но если мы определим универсальный, то он будет отображаться в methods() результатах:

> foo = function(object, ...) UseMethod("foo")
> methods(class = "merMod")
 [1] anova          as.function    coef           confint        cooks.distance
 [6] deviance       df.residual    drop1          extractAIC     family        
[11] fitted         fixef          foo            formula        getL          
[16] getME          hatvalues      influence      isGLMM         isLMM         
[21] isNLMM         isREML         logLik         model.frame    model.matrix  
[26] ngrps          nobs           plot           predict        print         
[31] profile        ranef          refit          refitML        rePCA         
[36] residuals      rstudent       show           sigma          simulate      
[41] summary        terms          update         VarCorr        vcov          
[46] weights       

Теперь он включает foo

Аналогично, в вашем примере, methods() покажетсуществование cld, если вы делаете library(multcomp), потому что именно там находится универсальное значение для cld.

...