R6 传递一个 self$FUN 作为参数

R6 pass a self$FUN as parameter

我正在开始构建一个“用户友好”的 R6 class 并希望让一个函数完成我 class 的大部分工作。这是我目前的结构

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 class:

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)

提前致谢:-)

以下实现将允许您通过三种方法中的任何一种调用您的函数。它通过使用 non-standard 评估来确定 FUN 是格式 x$func 还是只是一个裸露的 func。在任何一种情况下,它都采用裸函数名称并构建调用以将其转换为 self$func。然后它只计算该函数。

因此,以下 R6 class 在所有测试示例中都按预期工作:

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