【问题标题】:Pass function as parameter using tidy_eval/rlang context使用 tidy_eval/rlang 上下文将函数作为参数传递
【发布时间】:2019-12-05 06:31:28
【问题描述】:

我有一个想要传递给它的函数。但是,我似乎无法使用 tidy_eval 上下文使其工作。

这是一些数据:

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

我希望能够像这样调用函数:

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

其中第三个参数可以是任何不同的函数。

这是我第一次尝试编写函数:

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

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

上面给出了错误:

eval(., expr) 中的错误:'language' 类型的'envir' 参数无效`

如果我尝试:

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

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

我得到了错误

stri_detect_regex(string, pattern, negate = negate, opts_regex = opts(pattern)) 中的错误: 目的 '。'没找到

【问题讨论】:

    标签: r dplyr tidyverse rlang tidyeval


    【解决方案1】:

    如果您不想使用波浪线引号,则需要引用表达式并将其解析为 rlang::as_function 可以理解的形式,然后再转换它以便调用:

    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
    

    不过,这不是一个众所周知的习语;保持简单可能更好。

    【讨论】:

      【解决方案2】:

      如果您将函数作为带有波浪号 (~) 的公式传递,则可以使用 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
      

      【讨论】:

      • 我强烈推荐这个解决方案。使用元编程创建新语法很诱人,但这很少是正确的方法,因为它最终会使用户感到困惑。
      • 感谢您提供的非常有用的建议——效果很好。作为后续行动,假设我想在函数中为函数提供输入 - 即告诉它在哪个列上运行 str_detect,你知道我该怎么做吗?例如,func(A)
      • @JesseKerr 我不知道我的头顶,我现在没有时间研究它。 :) 也许问一个新问题?
      猜你喜欢
      • 1970-01-01
      • 2021-09-29
      • 2013-01-22
      • 2021-04-13
      • 1970-01-01
      • 2023-04-02
      • 2013-01-27
      相关资源
      最近更新 更多