В R: как передать имя функции (не как символ) в качестве аргумента другой внутренней функции без потери начального имени функции? - PullRequest
0 голосов
/ 05 июня 2018

У меня есть две функции:

  1. Worker, которая выполняет работу
  2. Boss, которая вызывает «Работника» и просит его выполнить данную функцию с именем name

Если я вызываю Worker напрямую, он получает тело функции и ее имя, поэтому он может использовать оба.Но если я вызываю Worker через Boss, Boss маскирует имя функции из Worker как FUN

require(magrittr)    
require(dplyr)

df <- data.frame(one = c(1,1,1), two = c(1,3,NA))

Worker <- function(df, feature, FUN, ...) {
  newvarname <- paste0(substitute(FUN), feature)
  df %>% mutate(!!newvarname := FUN(!!as.name(feature), ...))
}

Boss <- function(df, feature, FUN, ...) {
  df %>% Worker(feature, FUN, ...)
}

Boss(df, "two", mean, na.rm = T)
   #   one two FUNtwo
   # 1   1   1      2
   # 2   1   3      2
   # 3   1  NA      2
Worker(df, "one", mean)
   #   one two meanone
   # 1   1   1       1
   # 2   1   3       1
   # 3   1  NA       1

Я устал играть с quote/quo/enquo/substitute/get/match.fun, но ничегопомог.Означает ли это, что R не может передать целый объект функции - и имя, и тело - в качестве аргумента?

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Вот один из способов справиться с этим с помощью rlang:

library(rlang)

df <- data.frame(one = c(1,1,1), two = c(1,3,NA))

Worker <- function(df, feature, FUN, ...) {

    if (!is_quosure(FUN)) {
        fun_q <- quo(FUN)
        newvarname <- paste0(substitute(FUN), feature)
    }
    else {
        fun_q <- FUN
        newvarname <- paste0(quo_text(fun_q), feature)
    }

    df %>% mutate(!!newvarname := eval(fun_q)(!!as.name(feature), ...))
}

Boss <- function(df, feature, FUN, ...) {
    fun_q <- enquo(FUN)
    df %>% Worker(feature, fun_q, ...)
}

Boss(df, "two", mean, na.rm = T)

  one two meantwo
1   1   1       2
2   1   3       2
3   1  NA       2

Worker(df, "one", mean)

  one two meanone
1   1   1       1
2   1   3       1
3   1  NA       1
0 голосов
/ 05 июня 2018

Вы можете добавить eval(substitute()) внутри Boss, но это не выглядит очень удовлетворительным

Boss <- function(df, feature, FUN, ...) {
  eval(substitute(df %>% Worker(feature, FUN,...)))
}

Boss(df, "two", mean, na.rm = T)
  one two meantwo
1   1   1       2
2   1   3       2
3   1  NA       2
...