Какая польза от логического (), двойного () и т. Д. В качестве значения аргумента по умолчанию - PullRequest
0 голосов
/ 27 февраля 2019

Переписано после @G.Ответ Гротендика

В Advanced R , о S3 классах , я наткнулся на следующее определение функции:

new_Date <- function(x = double()) {
  stopifnot(is.double(x))
  structure(x, class = "Date")
}

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

Чтение @G.Ответ Гротендика, я понимаю, что double() это двойной NA .Означает ли это, что использование double() только для того, чтобы функция могла работать с (пустым) двойным числом, даже если аргумент не предоставлен (вместо бросания отсутствует аргумент ошибка), и не имеет ничего дляделать с проверкой класса x?

Исходный вопрос

Иногда я вижу функции, определенные со значениями по умолчанию для аргументов, как пустой (или фиксированной длины) тип, как таковой:

func1 <- function(a = logical(), b = numeric(1)){
    if (a){
        b
    } else {
        0
    }
}

Я понимаю, что это упрощает чтение, чтобы знать, какой тип каждого аргумента.Но, похоже, аргумент не будет такого типа.

func1(a = 4, b = 3)
# 3
func1(a = 4, b = TRUE)
# TRUE

Я знаю, что если в этом конкретном примере я поменяю if (a) на if (a == TRUE), это вызовет ошибку, если a не является логическим.Но в целом, если нет проверки типа аргументов внутри тела функции, какова польза от этого типа определения аргумента?

Я бы предпочел подобный тип определения функции, но это далекотяжелее:

func2 <- function(a, b){
    if (class(a) != 'logical') stop('a must be logical')
    if (!(class(b) == 'numeric' & length(b) == 1)) stop(
        'b must be numeric(1)'
    )
    ...
}

1 Ответ

0 голосов
/ 27 февраля 2019

stopifnot

Если предположить, что если a является логическим NA, то он все равно должен вернуть 0, тогда попробуйте это (или замените вторую строку тела на a * b, если логический NA для aдолжен вернуть НС).

Во всяком случае, главное в том, что для проверки аргументов можно использовать следующий стиль stopifnot.

func2 <- function(a, b) {
  stopifnot(is.logical(a), is.numeric(b))
  isTRUE(a) * b
}

func2(TRUE, 3)
## [1] 3

func2(9, 2)
## Error in func2(9, 2) : is.logical(a) is not TRUE

Вместо stopifnot используйте if (...) stop(...), один такой оператор нааргумент, если вам нужны пользовательские сообщения об ошибках.

S3 и S4

Обратите внимание, что можно использовать S3 для отправки в метод на основе первого аргумента или S4 для отправки в данную сигнатуру,Если метод для такой подписи не существует, будет вызвана ошибка.

Вот пример S4:

setMethod("func3", c("logical", "numeric"), function(a, b) isTRUE(a) * b)

func4(TRUE, 3)
## [1] 3

func4(2, 1)
## Error in UseMethod("func3") : 
##  no applicable method for 'func4' applied to an object of class "c('double', 'numeric')"

Вот пример S3:

# check 1st arg using S3 dispatch and 2nd arg using stopifnot
func3 <- function(a, b) UseMethod("func4")
func3.logical <- function(a, b) {
  stopifnot(is.numeric(b))
  isTRUE(a) * b
}

func3(TRUE, 3)
## [1] 3

func3(3, 8)
## Error in UseMethod("func3") : 
##  no applicable method for 'func3' applied to an object of class "c('double', 'numeric')"

Other

В CRAN есть пакет с именем checkmate для проверки аргументов, которая используется довольно многими другими пакетами (заменяя ныне несуществующий ArgumentCheck пакет).Еще один пакет для проверки типов аргументов - TypeInfo на Bioconductor.

Существует пакет с именем rtype для строгой проверки типов.

Также есть пакеты assertive.types , assertive , assertr , assertable и assertthat для утверждений типа.

Также обратите внимание, что в отношении кода в вопросе о том, что класс S3 является вектороми поэтому может иметь более одного элемента, поэтому используйте is.someclass (если такая функция существует для someclass) или inherits(X, "someclass"), где someclass - интересующий класс, а не class(X) == "someclass" для проверки классов S3.

...