带有缺少参数的方法调度

时间:2014-03-11 14:37:55

标签: r arguments s4 optional-arguments method-dispatch

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


实施例

大图

  • 有一个调用方法foo()的方法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语句,我不太喜欢它。整个&#34; if-else逻辑&#34;已经进入了bar()的各种方法的规范。毕竟,首先要有一个方法调度员,对吧?因此,我会将这些陈述视为&#34;不受欢迎的工作&#34;我正在寻找更好的方法。

当然,人们可以使用NULL作为所有&#34;关键&#34;的默认值。参数,但我希望尽可能依赖missing()代替is.null()

1 个答案:

答案 0 :(得分: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