Search code examples
rdplyrquoting

In R: how to pass function name (not as character) as an argument to another inner function without loss of initial function name?


I have two functions:

  1. Worker that does the job
  2. Boss that calls the "Worker" and ask it to execute given function called by name

If I call Worker directly it receives function body and its name so it can use both. But if I call the Worker through the Boss, the Boss masks name of the function from the Worker as 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

I tired to play with quote/quo/enquo/substitute/get/match.fun, but nothing helped. Does it mean, that R cannot pass a whole function object - both name and body - as an argument?


Solution

  • Here is one way to handle it with some 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