R 在不使用字符串操作的情况下将函数调用包装到另一个调用中

R wrap function call into another call without using string manipulation

我正在寻找一种将函数调用包装到另一个函数调用中的好方法。在调用其他函数之前包装一个函数很容易,但修改现有调用对我来说似乎不是那么直接。

我找到了一种使用下面的示例进行解释的方法,但它基本上依赖于将调用转换为列表转换为字符串,然后将新调用添加为字符串并使用 [=11 将所有内容转换回语言=].

有更简洁的方法吗?

假设我正在为 dplyr 构建自定义 summarise 函数,它将检查输出是否为向量,在这种情况下,使用 [= 创建一个 df-col 15=] 在现有呼叫上。

这是代表。

library(tidyverse)

short_sum <- function(data, ...) {

  fns <- rlang::enquos(...)

  fns <- purrr::map(fns, function(x) {

    res <- rlang::eval_tidy(x, data = data)

    if ((is.vector(res)  || is.factor(res)) && length(res) > 1) {

      # is there a better way to do this (start) ---
      # get expression of call and turn it into a string
      x_expr <- as.character(list(rlang::quo_get_expr(x)))

      # construct a string with expression above wrapped in another call
      x_expr <- paste0(
        "pivot_wider(enframe(",
        x_expr,
        "), names_from = name, values_from = value)"
      )

      # turn string into language and replace expression in x
      x <- rlang::quo_set_expr(x, str2lang(x_expr))
      # is there a better way to do this (end) ---

      x
    } else {
      x
    }
  })

    dplyr::summarise(data, !!! fns, .groups="drop")
}


mtcars %>% 
  as_tibble %>% 
  short_sum(quant = quantile(mpg),
            range = range(wt))

#> # A tibble: 1 x 2
#>   quant$`0%` $`25%` $`50%` $`75%` $`100%` range$`1`  $`2`
#>        <dbl>  <dbl>  <dbl>  <dbl>   <dbl>     <dbl> <dbl>
#> 1       10.4   15.4   19.2   22.8    33.9      1.51  5.42

reprex package (v0.3.0)

于 2020-06-14 创建

这个问题是基于我的回答,我在其中使用了上面的方法。

我不是 100% 确定该函数的作用,但我认为您可能正在寻找这样的东西:

short_sum <- function(data, ...) {

  fns <- rlang::enquos(...)

  fns <- purrr::map(fns, function(x) {
    res <- rlang::eval_tidy(x, data = data)

    if ((is.vector(res)  || is.factor(res)) && length(res) > 1) {
      rlang::expr(pivot_wider(enframe(
        !!rlang::quo_get_expr(x)), names_from = name, values_from = value))
      # or
      # bquote(pivot_wider(enframe(
      #  .(rlang::quo_get_expr(x))), names_from = name, values_from = value))
    } else {
      x
    }
  })

  dplyr::summarise(data, !!! fns, .groups="drop")
}

expr() 类似于 quote(),只是您可以使用 !!!!! 取消对表达式部分的引用。

bquote() 也类似于 quote(),但在基础 R 中,您使用 .() 取消引用。