R6 передает self $ FUN в качестве параметра

#r #r6

#r #r6

Вопрос:

Я начинаю создавать «удобный» класс R6 и хочу, чтобы функция выполняла большую часть работы моего класса. Пока это моя структура

 x <- X$new()
veggie_cubes <- veggie %>% x$cubesX(ID)
veggie_slices <- veggie %>% x$sliceX(ID)
  

Теперь мой вопрос в том, можно ли переписать код таким образом, чтобы:

 x <- X$new()
veggie_cubes <- veggie %>% x$cutX(cubesX, ID)
veggie_slices <- veggie %>% x$cutX(sliceX, ID)
  

Заголовок функции должен выглядеть как: cut(.data, FUN, KEY)

До сих пор моя идея состояла в том, чтобы написать cut , как:

 cutX= function(.data, FUN, KEY)
{
   .data %>%
     FUN({{ KEY }}) %>%
     base::return()
}
  

Единственным способом, которым это работает, был вызов veggie %>% x$cutX(x$cubesX, ID) , который я бы не предпочел как «удобное для пользователя» решение, мне также не очень нравится использовать для этого строки. Есть ли способ записать его без x$ ?

вот упрощенный класс R6:

 X <- R6::R6Class(
  classname = "X",
  public = base::list(
    cubesX = function(.data, KEY)
    {
      .data %>% 
        dplyr::select(!{{ KEY }}) %>% 
        base::return()
    },
    sliceX = function(.data, KEY)
    {
      .data %>% 
        dplyr::select({{ KEY }}) %>% 
        base::return()
    },
    cutX = function(.data, FUN, KEY)
    {
      .data %>% 
        FUN( {{ KEY}}) %>% 
        base::return()
    }
  )
)
  

примеры выполнения:

 x <- X$new()
iris %>% x$sliceX(Species)
iris %>% x$cubesX(Species)
# with FUN
iris %>% x$cutX(x$sliceX, Species)
iris %>% x$cutX(x$cubesX, Species)
  

не выполняется:

 iris %>% x$cutX(sliceX, Species)
iris %>% x$cutX(cubesX, Species)
  

Заранее спасибо 🙂

Комментарии:

1. Не могли бы вы опубликовать код для определения вашего класса R6, пожалуйста?

Ответ №1:

Следующая реализация позволит вам вызывать ваши функции с помощью любого из ваших трех методов. Он работает с использованием нестандартной оценки, чтобы выяснить, находится ли FUN он в формате x$func или просто голый func . В любом случае он принимает голое имя функции и создает вызов для ее преобразования self$func . Затем он просто оценивает эту функцию.

Поэтому следующий класс R6 работает, как и ожидалось, во всех ваших тестовых примерах:

 X <- R6::R6Class(
  classname = "X",
  public = base::list(
    cubesX = function(.data, KEY)
    {
      .data %>% 
        dplyr::select(!{{ KEY }}) %>% 
        base::return()
    },
    sliceX = function(.data, KEY)
    {
      .data %>% 
        dplyr::select({{ KEY }}) %>% 
        base::return()
    },
    cutX = function(.data, FUN, KEY)
    {
      if(is.call(substitute(FUN))) {
        FUN <- substitute(FUN) 
        FUN[[2]] <- quote(self)
      }
      else 
        FUN <- as.call(list(quote(`$`), quote(self), substitute(FUN)))
 
      eval(as.call(list(FUN, quote(.data), substitute(KEY))))
    }
  )
)
  

Так, например:

 x <- X$new()
iris %>% x$cutX(sliceX, Species)

#>        Species
#> 1       setosa
#> 2       setosa
#> 3       setosa
#> 4       setosa
#> 5       setosa
#> 6       setosa
#> 7       setosa
#> 8       setosa
#> 9       setosa
#> 10      setosa
#> 11      setosa
#> 12      setosa
#> 13      setosa
#> 14      setosa
#> 15      setosa
#> 16      setosa
#> 17      setosa
#> 18      setosa
#> 19      setosa
#> 20      setosa
#> ...etc