Применение метода R только к * матрицам * определенного класса - PullRequest
5 голосов
/ 25 мая 2020

Пакет, который я разрабатываю, содержит метод R и функцию, которую я sh применяю только к числовым c матрицам.

Моя функция вызовет C функция, ожидающая на входе числовую матрицу c. Я хочу, чтобы авторы других пакетов могли легко писать отдельные обработчики для (скажем) чисел c векторов или символьных матриц без необходимости редактировать функцию в моем пакете.

Ради простого примера , скажем, я хочу, чтобы функция добавляла единицу к матрицам:

AddOne <- function (x) UseMethod('AddOne')
AddOne.[numeric-AND-matrix] <- function (x) add_one_in_c(x)

AddOne(1) # Should report "No applicable method"
AddOne(matrix("one")) # Should report "No applicable method"
AddOne(matrix(1)) # Should send the matrix to add_one_in_c()

Просто смотрю, является ли x числовым c или матрицей, слишком общим:

AddOne <- function (x) UseMethod('AddOne')
AddOne.numeric <- function (x) message("X is numeric, but may not be a matrix")
AddOne.matrix <- function (x) message("X is a matrix, but may not be numeric")

И меня отговаривали от использования inherits для такого рода целей:

AddOne <- function (x) UseMethod('AddOne')
AddOne.matrix <- function (x) {
  if (inherits(x, 'numeric')) {
    add_one_in_c(x)
  } else {
    NextMethod(x)
  }
}

Это последнее решение также было бы трудно расширить. Возможно, кто-то другой сможет обработать символьные матрицы, написав AddOne.character(), но эта функция также должна будет обрабатывать символьные векторы.

Есть ли способ сделать это, в полной мере использующий протоколы методов?

Ответы [ 2 ]

2 голосов
/ 25 мая 2020

Вы можете определить метод по умолчанию, который обрабатывает все, кроме матриц. Затем в матричном методе, если это что-то другое, кроме numeri c, вы просто вызываете NextMethod, который вызывает метод по умолчанию. Поэтому вам нужно написать только одно сообщение об ошибке и один матричный метод.

# Here's a stand in for your C function:
add_one_in_c   <- function(x) x + 1

AddOne         <- function(x) UseMethod('AddOne')
AddOne.default <- function(x) stop("No applicable method")
AddOne.matrix  <- function(x) if (is.numeric(x)) add_one_in_c(x) else NextMethod()

Итак, протестировав его, мы получим:

char_matrix <- matrix(LETTERS[1:9], nrow = 3)
num_matrix  <- matrix(1:9, nrow = 3)

AddOne(num_matrix)
#>      [,1] [,2] [,3]
#> [1,]    2    5    8
#> [2,]    3    6    9
#> [3,]    4    7   10

AddOne(char_matrix)
#>  Error in AddOne.default(char_matrix) : No applicable method

AddOne(1:9)
#>  Error in AddOne.default(1:9) : No applicable method

Дополнение

Другой способ сделать это, упрощая добавление методов для других классов по мере необходимости, - использовать функцию AddOne в качестве «привратника», который гарантирует, что обрабатываются только матрицы, и который затем отправляет S3 метод в соответствии с классом базовых данных:

add_one_in_c   <- function(x) x + 1

AddOne  <- function(x) 
{
  if(class(x) != "matrix") stop("No applicable method")
  return(AddOne_basic(as.vector(x), nrow(x), ncol(x)))
}

AddOne_basic <- function(x, r, c) UseMethod("AddOne_basic")

AddOne_basic.default <- function(x, r, c) stop("No appicable method")

AddOne_basic.numeric <- function(x, r, c) {
  dim(x) <- c(r, c); 
  add_one_in_c(x)
}

Итак, чтобы расширить обработку AddOne на другие базовые c типы, вы добавляете соответствующий метод AddOne_basic. Очевидно, что при написании пакета вы можете решить не экспортировать "внутренние" AddOne_basic методы.

0 голосов
/ 25 мая 2020

Я не знаю, не стоит ли это также обескураживать, но не могли бы вы просто протестировать вот так:

AddOne.matrix <- function (x) {
  all(methods::is(x[1], 'numeric'), methods::is(x, 'matrix')) {
    add_one_in_c(x)
  } else {
    NextMethod(x)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...