R RefClass наследовать от списка - PullRequest
1 голос
/ 06 мая 2020

Следующая ситуация: если я определяю RefClass в R и использую стандартный list в качестве суперкласса следующим образом:

A <- setRefClass(
  Class = "A",
  contains = "list",
  fields = c(
    a = "numeric"
  )
)
# works fine at first 
aObj <- A()
str(aObj)
aObj[[1]] <- "a1"
aObj[[2]] <- "a2"
length(aObj)
unlist(aObj)

сначала все работает нормально, но методы show выдают ошибку

> aObj <- A()
> aObj
> Error in { : could not find function "{"
> aObj[[1]] <- "a1"
> aObj
> Error in list2env(new("A", .Data = list("a1"), .xData = <environment>),  : 
names(x) must be a character vector of the same length as x

Я понятия не имею о первой ошибке, а для второй я безуспешно пытался исправить ее следующим образом:

setMethod("names", signature = ".A", definition = function(x){
  paste("A",1:base::length(x), sep="")
})

Есть ли способ заставить вышеуказанное работать правильно? Я знаю, что, вероятно, нецелесообразно наследовать от стандартного класса, но каковы альтернативы реализации класса настраиваемого списка без повторной реализации функций общего списка?

1 Ответ

0 голосов
/ 01 июля 2020

Учитывая ваши заявленные намерения, я не думаю, что ссылочные классы - это то, что вы здесь ищете. Ссылочные классы могут быть очень эффективными для многих случаев использования, но если ваша цель - сохранить интерфейс в виде списка для вашего нового класса, т. Е. Он может обращаться к функциям generi c, как если бы это был список, вам следует поискать в другом месте.

Любой создаваемый вами объект ссылочного класса представляет собой особый тип среды. Для начала это означает, что стандартное подмножество списка, например aObj[[1]], просто не будет работать. Единственная причина, по которой ваш пример позволяет вам это сделать, заключается в том, что ваше определение A не работает и фактически не возвращает правильный объект ссылочного класса:

A <- setRefClass(
  Class = "A",
  contains = "list",
  fields = c(
    a = "numeric"
  )
)

aObj <- A()
is.environment(aObj)
#> [1] FALSE

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

Теперь вы могли бы реализовать ссылочный класс, где основным элементом данных является список и разделяет некоторые функции списка вот так:

A <- setRefClass(
  Class = "A",
  fields = c(a = "list"),
  methods = list(
      
    show = function() {
            cat("A special list of type A containing:\n");
            methods::show(.self$a)
    },
    append = function(x) {.self$a <- base::append(.self$a, x); return(.self)}
  )
)

# Functions to convert back and forwards between A and normal list
as.list.A <- function(x) x$a
as.A      <- function(x) A(a = as.list(x))


aObj <- A()
aObj
#> A special list of type A containing:
#> list()

aObj$append(1:3)
#> A special list of type A containing:
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] 2
#> 
#> [[3]]
#> [1] 3

Но это не решает вашу проблему, связанную с желанием иметь возможность доступа путем разделения на подмножества или наследования полезных характеристик списка. Итак, что вы можете сделать?

Я думаю, что с точки зрения функциональности вы ищете класс S3. Возможно, реализация чего-то вроде этого, где мы просто определяем простой конструктор объекта и несколько обобщений:

A <- function(a = numeric()) structure(list(a = a), class = c("A", "list"))

as.list.A <- function(x) {class(x) <- "list"; x;}

str.A <- function(x) cat("A magical list of wonders called", 
                         deparse(substitute(x)), "\n")

print.A <- function(x) {
  cat("A special list of type A containing:\n")
  print(as.list(x))
}

, который ведет себя следующим образом:

aObj <- A(a = 1:3)

aObj
#> A special list of type A containing:
#> $a
#> [1] 1 2 3

aObj[[1]] <- 1:4
aObj[[2]] <- 2:5

aObj
#> A special list of type A containing:
#> $a
#> [1] 1 2 3 4
#> 
#> [[2]]
#> [1] 2 3 4 5
  
str(aObj)
#> A magical list of wonders called aObj

Потому что aObj эффективно наследуется от list, любые общие c функции, которые вы не объявили, будут использовать общие c методы, как если бы это был обычный список. Это позволяет вам делать такие вещи, как:

lapply(aObj, mean)
#> $a
#> [1] 2.5
#> 
#> [[2]]
#> [1] 3.5

Создано 01.07.2020 пакетом REPEX (v0.3.0)

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