Каковы рекомендуемые практики для полиморфизма функций в 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
}

Я склоняюсь к первому, я думаю

2 ответа

Решение

Вы также можете встраивать функции в аргументы, как:

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, С помощью NA а также is.na() будет вести себя странно для векторных входов, тогда как NULL это просто один объект - нельзя создать вектор значений NULL, поэтому is.null(argument) ведет себя как ожидалось. Извиняюсь за забывчивость.

R способ реализации полиморфизма - через модель CLOS (OO Common Lisp), где методы связаны с общими функциями (глаголами), а не с классами (существительными). Например,

# 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 ООП модель, которой я считаю вполне достаточной; S4 является более современным и безопасным, но добавляет много шаблонного.

Другие вопросы по тегам