I'm trying to run this function with exec(). I have a workaround that uses rlang::expr and then !! but that implies changing the function to accept an expression as an argument instead of a quoted variable. Is there a way to call this function without loosing the ability to pass quoted arguments?
library(tidyverse)
calc_mean <- function(df, col) {
df %>%
summarise(mean({{ col }}))
}
#doesn't work
map(list('calc_mean'), ~exec(.x, df = mtcars, col = mpg))
#> Warning in mean.default(~structure(list(manufacturer = c("audi", "audi", :
#> argument is not numeric or logical: returning NA
#> [[1]]
#> mean(...)
#> 1 NA
Created on 2022-01-15 by the reprex package (v2.0.1)
My expected output would be the same as calling the function outside exec:
calc_mean(mtcars, mpg)
#> mean(mpg)
#> 1 20.09062
CodePudding user response:
I expect you want to loop over a list of function names and this is just a minimal example (otherwise there would be no need for map).
We could use base R do.call, but we'd have to quote the arguments and put them in a list:
library(tidyverse)
calc_mean <- function(df, col) {
df %>%
summarise(mean({{ col }}))
}
map(list("calc_mean"), ~ do.call(.x, list(df = quote(mtcars), col = quote(mpg))))
#> [[1]]
#> mean(mpg)
#> 1 20.09062
Another possible approach is to work with get or mget (if you have a vector of function names) and then we can do something crazy. We just call .x as a function in your lambda function. No list or quote needed. It is best practice to specify the envir argument of get which I skipped in the minimal example below:
map(list(get("calc_mean")), ~ .x(df = mtcars, col = mpg))
#> [[1]]
#> mean(mpg)
#> 1 20.09062
Created on 2022-01-15 by the reprex package (v0.3.0)
