Использование определенных типов данных в качестве аргументов функции - PullRequest
10 голосов
/ 21 августа 2011

Мне было просто интересно, есть ли способ заставить функцию принимать только определенные типы данных, не проверяя ее внутри функции; или это невозможно, потому что проверка типов в R выполняется во время выполнения (в отличие от тех языков программирования, как Java, где проверка типов выполняется во время компиляции)?

Например, в Java вы должны указать тип данных:

class t2 {
    public int addone (int n) {
        return n+1;
    }
}

В R похожая функция может быть

addone <- function(n)
{
    return(n+1)
}

но если указан вектор, вектор (очевидно) будет возвращен. Если вы хотите, чтобы принималось только одно целое число, то это единственный способ сделать условие внутри функции в соответствии с

addone <- function(n)
{
  if(is.vector(n) && length(n)==1)
  {
    return(n+1)
  } else
  {
    return ("You must enter a single integer")
  }
}

Спасибо
Chris

Ответы [ 3 ]

18 голосов
/ 21 августа 2011

Это вполне возможно при использовании классов S3. Ваш пример несколько надуманный в контексте или R, поскольку я не могу придумать практическую причину, почему кто-то хотел бы создать класс с одним значением. Тем не менее, это возможно. В качестве дополнительного бонуса я продемонстрирую, как можно использовать функцию addone для добавления значения единицы к числовым векторам (тривиальным) и символьным векторам (поэтому A превращается в B и т. Д.):

Начните с создания общего метода S3 для addone, используя механизм отправки S3 UseMethod:

addone <- function(x){
  UseMethod("addone", x)
}

Затем создайте надуманный класс single, определенный как первый элемент всего, что ему передано:

as.single <- function(x){
  ret <- unlist(x)[1]
  class(ret) <- "single"
  ret
}

Теперь создайте методы для обработки различных классов. Метод по умолчанию будет вызываться, если не определен определенный класс:

addone.default <- function(x) x + 1
addone.character <- function(x)rawToChar(as.raw(as.numeric(charToRaw(x))+1))
addone.single <- function(x)x + 1

Наконец, протестируйте его с некоторыми примерами данных:

addone(1:5)
[1] 2 3 4 5 6

addone(as.single(1:5))
[1] 2
attr(,"class")
[1] "single"

addone("abc")
[1] "bcd"

Некоторая дополнительная информация:

  1. Wiki Хэдли devtools является ценным источником информации обо всех вещах, включая систему объектов S3 .

  2. Метод S3 не обеспечивает строгой типизации. Это может быть легко злоупотреблено. Для более строгой ориентации объекта ознакомьтесь с S4 классами , ссылочными классами или протопакетом для объектного программирования Prototype.

5 голосов
/ 22 августа 2011

Я обнаружил, что stopifnot () очень полезен и для этих ситуаций.

x <- function(n) { 
stopifnot(is.vector(n) && length(n)==1)
print(n)
}

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

4 голосов
/ 21 августа 2011

Вы можете написать обертку следующим образом:

check.types = function(classes, func) {
    n = as.name

    params = formals(func)
    param.names = lapply(names(params), n)

    handler = function() { }
    formals(handler) = params

    checks = lapply(seq_along(param.names), function(I) {
        as.call(list(n('assert.class'), param.names[[I]], classes[[I]]))
    })
    body(handler) = as.call(c(
        list(n('{')),
        checks,
        list(as.call(list(n('<-'), n('.func'), func))),
        list(as.call(c(list(n('.func')), lapply(param.names, as.name))))
    ))

    handler
}

assert.class = function(x, cls) {
    stopifnot(cls %in% class(x))
}

И использовать ее как

f = check.types(c('numeric', 'numeric'), function(x, y) {
    x + y
})

> f(1, 2)
[1] 3

> f("1", "2")
Error: cls %in% class(x) is not TRUE

Сделано несколько неудобно из-за того, что R не имеет декораторов.Это отчасти хакерство и страдает от некоторых серьезных проблем:

  1. Вы теряете ленивую оценку, потому что вы должны оценить аргумент, чтобы определить его тип.

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

Поскольку R использует отложенную оценку, (2) может сделать проверку типа не очень полезной, поскольку вызовна самом деле может не произойти до очень позднего или никогда.

Ответом на (2) будет добавление статической информации о типе.Вероятно, вы могли бы сделать это путем преобразования выражений, но я не думаю, что вы хотите туда идти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...