如何在给定S4方法中明确地将参数值分派给后续S4方法时,如何避免经典Error: argument "<argname>" is missing, with no default错误(参见下面的示例)。
例
大图
有一个方法foo()调用方法bar() 。 两种方法都依赖于参数x和y 。 方法foo()以显式方式将参数x和y调度到bar() : bar(x=x, y=y) 。现在,关键点在于我不希望foo()关注是否缺少传递给bar()任何或所有参数。
通用方法
setGeneric( name="foo", signature=c("x", "y"), def=function(x, y, ...) { standardGeneric("foo") } ) setGeneric( name="bar", signature=c("x", "y"), def=function(x, y, ...) { standardGeneric("bar") } )bar()方法bar()
setMethod( f="bar", signature=signature(x="missing", y="missing"), definition=function(x, y, ...) { print("Doing what I'm supposed to do when both args are missing") return(NULL) } ) setMethod( f="bar", signature=signature(x="ANY", y="missing"), definition=function(x, y, ...) { message("'y' is missing, but I can give you 'x':") print(x) return(NULL) } ) setMethod( f="bar", signature=signature(x="missing", y="ANY"), definition=function(x, y, ...) { message("'x' is missing, but I can give you 'y':") print(y) return(NULL) } ) setMethod( f="bar", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { message("x:") print(x) message("y:") print(y) return(NULL) } )foo()
如上所述,我不希望foo()关注是否缺少传递给bar()任何或所有参数。 它应该以明确的方式将所有内容传递给bar() :
setMethod( f="foo", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { bar(x=x, y=y) } )解决方法
到目前为止,这是我能提出的唯一解决方法:
setMethod( f="foo", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { if (missing(x) && missing(y)) { bar() } else if (missing(x)) { bar(y=y) } else if (missing(y)) { bar(x=x) } else { bar(x=x, y=y) } } ) > foo(x="Hello", y="World!") x: [1] "Hello" y: [1] "World!" NULL > foo(x="Hello") 'y' is missing, but I can give you 'x': [1] "Hello" NULL > foo(y="World!") 'x' is missing, but I can give you 'y': [1] "World!" NULL > foo() [1] "Doing what I'm supposed to do when both args are missing" NULLBig picture
Whe have a method foo() that calls method bar(). Both methods depend on arguments x and y. Method foo() dispatches arguments x and y to bar() in an explicit way: bar(x=x, y=y).Now, the crucial point here is that I don't want foo() to care if any or all of the arguments that are passed along to bar() are missing.
Generic methods
setGeneric( name="foo", signature=c("x", "y"), def=function(x, y, ...) { standardGeneric("foo") } ) setGeneric( name="bar", signature=c("x", "y"), def=function(x, y, ...) { standardGeneric("bar") } )Methods for bar()
setMethod( f="bar", signature=signature(x="missing", y="missing"), definition=function(x, y, ...) { print("Doing what I'm supposed to do when both args are missing") return(NULL) } ) setMethod( f="bar", signature=signature(x="ANY", y="missing"), definition=function(x, y, ...) { message("'y' is missing, but I can give you 'x':") print(x) return(NULL) } ) setMethod( f="bar", signature=signature(x="missing", y="ANY"), definition=function(x, y, ...) { message("'x' is missing, but I can give you 'y':") print(y) return(NULL) } ) setMethod( f="bar", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { message("x:") print(x) message("y:") print(y) return(NULL) } )Method for foo()
As mentioned above, I don't want foo() to care if any or all of the arguments that are passed along to bar() are missing. It is just supposed to pass everything along to bar() in an explicit manner:
setMethod( f="foo", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { bar(x=x, y=y) } )Workaround
This is the only workaround that I could come up with so far:
setMethod( f="foo", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { if (missing(x) && missing(y)) { bar() } else if (missing(x)) { bar(y=y) } else if (missing(y)) { bar(x=x) } else { bar(x=x, y=y) } } ) > foo(x="Hello", y="World!") x: [1] "Hello" y: [1] "World!" NULL > foo(x="Hello") 'y' is missing, but I can give you 'x': [1] "Hello" NULL > foo(y="World!") 'x' is missing, but I can give you 'y': [1] "World!" NULL > foo() [1] "Doing what I'm supposed to do when both args are missing" NULLIt works, but I don't really like it because of all the if ... else statements. The whole "if-else logic" already went in the specification of the various methods for bar(). After all, that's the whole point of having a method dispatcher in the first place, right? Hence I would consider the statements as "undesired work" and I'm looking for a better way.
One could of course resort to to using NULL as default value for all "critical" arguments, but I would like to rely on missing() instead of is.null() in my functions as much as possible.
最满意答案
这是另一种想法。 (它广泛受到许多R模型拟合函数所使用的“语言计算”的启发。)
setMethod( f="foo", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { mc <- match.call() mc[[1]] <- quote(bar) eval(mc) } ) foo(x="Hello") # 'y' is missing, but I can give you 'x': # [1] "Hello" # NULL foo(y="World") # 'x' is missing, but I can give you 'y': # [1] "World" # NULL foo() # [1] "Doing what I'm supposed to do when both args are missing" # NULLHere is an alternative idea. (It's broadly inspired by the sort of "computing on the language" used by many of R's model-fitting functions.)
setMethod( f="foo", signature=signature(x="ANY", y="ANY"), definition=function(x, y, ...) { mc <- match.call() mc[[1]] <- quote(bar) eval(mc) } ) foo(x="Hello") # 'y' is missing, but I can give you 'x': # [1] "Hello" # NULL foo(y="World") # 'x' is missing, but I can give you 'y': # [1] "World" # NULL foo() # [1] "Doing what I'm supposed to do when both args are missing" # NULL更多推荐
发布评论