在R中,函数多态的建议实践是什么?



假设我想在R中写一个函数,它是一些数据的一对充分统计量的函数。例如,假设函数foo.func只依赖于数据样本的样本均值。为了方便,我认为用户可能喜欢将随机变量的样本传递给foo.func(在这种情况下,foo.func计算样本均值),样本均值本身,这就是foo.func所需要的。出于效率的考虑,如果调用foo.func等多个可以取样本均值的函数,则首选后者。在这种情况下,平均值只需要计算一次(在我遇到的实际问题中,所讨论的样本统计可能是计算密集型的)。

总之,我想把foo.func写得对初学者(传入数据,让函数计算充分统计)和专家(为了效率预先计算充分统计并传入)都可以访问。推荐的做法是什么?我有一个逻辑标志传入吗?多个参数?有些方法可以这样做:

#optional arguments
foo.func <- function(xdata, suff.stats=NULL) {
  if (is.null(suff.stats)) {
    suff.stats <- compute.suff.stats(x)
  }
  #now operate on suff.stats
}

#flag input
foo.func <- function(data.or.stat, gave.data=TRUE) {
  if (gave.data) {
    data.or.stat <- compute.suff.stats(data.or.stat)
  }
  #now operate on data.or.stat
}

我倾向于前者,我认为

R实现多态性的方式是通过CLOS (Common Lisp的OO)模型,其中方法与泛型函数(动词)而不是类(名词)相关联。例如,

# suprising that there is not an equivalent function in R
# to propagate inheritance...
addclass <- function(x,classname) structure(x,class=append(class(x),classname))
# this should be your main function that does stuff
# here, the identity function is assigned for example
dostuff <- identity
# define generic function and methods
foo <- function(x,...) UseMethod("foo")
foo.raw <- function(x,...) dostuff(mean(x))
foo.stats <- function(x,...) dostuff(x)
# define two types of inputs
x <- 1:10
x <- addclass(x,"raw")
y <- 5
y <- addclass(y,"stats")
# apply
foo(x)
# [1] 5.5
foo(y)
# [1] 5
# attr(,"class")
# [1] "numeric" "stats"  

这个例子使用了R的S3 OOP模型,我认为这已经足够了;S4更现代和安全,但增加了很多样板文件。

还可以在参数中嵌入函数,如:

foo.func <- function(x, suff.stats = foo.func.suff.stat(x)){
  # your code here
}

例如:

foo.func <- function(x, avg = mean(x)){
  return(avg)
}
foo.func(1:20)
foo.func(avg = 42)

或者,您可以对各种参数使用NULL的默认设置,并测试is.null(argument),或者简单地检查missing(argument)的值对于您可能计算的每个参数。


更新1:我错误地建议使用默认值NA:使用NULL要合适得多。使用NAis.na()对于矢量输入会表现得很奇怪,而NULL只是一个单独的对象——不能创建NULL值的矢量,所以is.null(argument)的行为和预期的一样。对不起,我忘了。