4

在给定 S4 方法中将参数值显式分派给后续 S4 方法时,如何避免经典Error: argument "<argname>" is missing, with no default错误(参见下面的示例) 。


例子

大图

  • 有一个foo()调用 method的方法bar()
  • 这两种方法都依赖于参数xy.
  • 方法以显式foo()方式分派参数xy到:.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()

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)    
    }
)

方法 def 乍一看可能看起来不错,但如果调用它xy缺少它,它就会失败:

> foo(x="Hello", y="World!")
x:
[1] "Hello"
y:
[1] "World!"
NULL
> foo(x="Hello")
Error in bar(x = x, y = y) : 
  error in evaluating the argument 'y' in selecting a method for function 'bar': Error: argument "y" is missing, with no default
> foo()
Error in bar(x = x, y = y) : 
  error in evaluating the argument 'x' in selecting a method for function 'bar': Error: argument "x" is missing, with no default

解决方法

到目前为止,这是我能想到的唯一解决方法:

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"
NULL

if ... else它有效,但由于所有的陈述,我真的不喜欢它。整个“if-else 逻辑”已经包含在bar(). 毕竟,这就是首先拥有一个方法调度器的全部意义,对吧?因此,我会将这些陈述视为“不受欢迎的工作”,我正在寻找更好的方法。

当然,可以求助于将NULL所有“关键”参数用作默认值,但我想尽可能多地依赖missing()而不是在我的函数中。is.null()

4

1 回答 1

4

这是一个替代的想法。(它的灵感来自于许多 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"
# NULL
于 2014-03-11T16:16:26.057 回答