穿针引线:找到与外部函数形式对应的实参名称

Threading the needle: finding the name of the actual argument corresponding to a formal of an outer function

下面的函数 strip() 试图通过三通管 (%T>%) 生成有关其操作结果的简短报告。因为这个函数依次被传递给包装函数,然后传递给 purrr::pwalk,它将一个接一个地提供一堆数据帧,我想得到它对每个数据帧的操作报告以及数据帧姓名;也就是说,提供的实际数据帧的名称与下面函数中的正式参数 tib 相对应。在提供的示例中,这将是 "tst_df"。我不知道函数 运行 之前的名称,因为它们是根据从磁盘读取的文件名和各种其他输入构造的。

令我有些惊讶的是,除了获取提供的数据框的名称外,我实际上几乎完成了所有这些工作。在下面的示例中,应该执行此操作的代码是 enexpr(XX),但我也尝试了 expr(XX),并且这两个表达式都应用于 tib 或点 (.), 有或没有前面的 !!。在 XXtib. 上也有 deparse(substitute()),但没有刘海。

我看到名称最初是通过按值传递剥离的,然后又一次,也许,通过管道的每个阶段,包括 T,再一次,也许,通过 (XX = .) 在T 之后的匿名函数中。但我知道 R + tidyverse 会有办法的。我只是希望它不涉及提供一个整数来向后计算调用堆栈

tst_df <- tibble(A = 1:10, B = 11:20, C=21:30, D = 31:40)
tst_df    
################################################################################
# The strip function expects a non-anonymous dataframe, from which it removes
# the rows specified in remove_rows and the columns specified in remove_cols. It
# also prints a brief report; just the df name, length and width.
strip <- function(tib, remove_rows = FALSE, remove_cols = NULL){
  remove_rows <- enquo(remove_rows)
  remove_cols <- enquo(remove_cols)
  out <- tib %>%
    filter(! (!! remove_rows))  %>%
    select(- !! remove_cols) %T>% (function(XX = .){
      function(XX = .)print(
          paste0("length of ", enxpr(XX), " = ", nrow(XX), " Width = ", ncol(XX)))
          cat("\n")
        })
  out  
}

out_tb <- strip(tib = tst_df, remove_rows = (A < 3 | D > 38),  remove_cols = c(C, D))
out_tb

只需在函数开头保存 tib 的名称, 它会被你的记者功能找到:

strip <- function(tib, remove_rows = FALSE, remove_cols = NULL) {
  remove_rows <- enquo(remove_rows)
  remove_cols <- enquo(remove_cols)
  tib_name <- as.character(substitute(tib))
  report <- function(out) {
    cat("output length of", tib_name, "=", nrow(out), ", width =", ncol(out), "\n")
  }

  tib %>%
    filter(! (!! remove_rows))  %>%
    select(- !! remove_cols) %T>%
    report
}

out_tb <- strip(tib = tst_df, remove_rows = (A < 3 | D > 38),  remove_cols = c(C, D))
output length of tst_df = 6 , width = 2