Jesse Kerr
Jesse Kerr

Reputation: 341

Pass function as parameter using tidy_eval/rlang context

I have a function that I want to pass a function to. However, I can't seem to get it to work using the tidy_eval context.

Here is some data:

df <- tribble(
  ~A, ~B,
  "hi", "hello",
  "bye", "later"
)

I want to be able to call the function like so:

my_quoting_fn(df, A, str_detect(., pattern = "h*"))

where the third parameter can be any different function.

Here is my first attempt to write the function:

my_quoting_fn <- function(df, col, func) {
  func <- enquo(func)
  expr <- quo_get_expr(func)

  df %>% 
    pull({{col}}) %>%
    eval(expr)

The above gives the error:

Error in eval(., expr) : invalid 'envir' argument of type 'language'`

If I try:

my_quoting_fn <- function(df, col, func) {

  df %>% 
    pull({{col}}) %>%
    {{func}}

I get the error

Error in stri_detect_regex(string, pattern, negate = negate, opts_regex = opts(pattern)) : object '.' not found

Upvotes: 3

Views: 276

Answers (2)

alistaire
alistaire

Reputation: 43334

If you don't want to tilde-quote, you'll need to quote the expression and parse it into a form rlang::as_function understands before converting it so it can be called:

library(tidyverse)

df <- tribble(
    ~A, ~B,
    "hi", "hello",
    "bye", "later"
)

my_quoting_fn <- function(df, col, func) {
    func <- enexpr(func) %>%    # only want the expression, not the environment of a quosure
        rlang::new_formula(NULL, .) %>%    # tilde-quote the expression
        rlang::as_function()    # make it a formula

    df %>% 
        pull({{col}}) %>% 
        func()
}

my_quoting_fn(df, A, str_detect(., pattern = "h*"))
#> [1] TRUE TRUE

This isn't a well-known idiom, though; keeping it simple is probably better.

Upvotes: 1

aosmith
aosmith

Reputation: 36076

If you pass your function as a formula with a tilde (~) you could use rlang::as_function().

my_quoting_fn <- function(df, col, func) {
    func = as_function(func)

    df %>%
        pull({{col}}) %>%
        func
}
my_quoting_fn(df, A, ~str_detect(., pattern = "h*"))
[1] TRUE TRUE

Upvotes: 4

Related Questions