【问题标题】:capture the environment of ellipsis/dots捕捉省略号/点的环境
【发布时间】:2022-10-23 22:54:08
【问题描述】:

{rlang} 有这个未导出的函数,可用于捕获省略号参数(名称、表达式和环境)。它赋予了rlang::enquos() 的魔力。

f <- function(...) rlang:::captureDots()

g <- function(...) f(..., b = z)

g(a = x, y)
#> $a
#> $a$expr
#> x
#> 
#> $a$env
#> <environment: R_GlobalEnv>
#> 
#> 
#> [[2]]
#> [[2]]$expr
#> y
#> 
#> [[2]]$env
#> <environment: R_GlobalEnv>
#> 
#> 
#> $b
#> $b$expr
#> z
#> 
#> $b$env
#> <environment: 0x130f8d8a8>

我想隔离,并希望理解这个功能,但我在 C 代码中找不到我的方式,在 rlang 中有很多它,似乎触及任何东西都会破坏一切。

我的要求是有一个最小的、高效的、自包含的方法来重新创建这个功能(有或没有来自 {rlang} 的灵感)。

在基础 R 中捕获名称和表达式很容易,但获取环境则不然。我不相信没有低级语言就可以做到这一点。

【问题讨论】:

  • 您是否查看过 rlang 源代码中 capture.c 中的 capturedots 函数?
  • 实际上,rlang_capturedots 似乎是捕获环境的位置,环境是args 参数的CAR
  • 是的,我可以追踪 captureDots -> ffi_capturedots -> rlang_capturedots (和 r_node_cdr) -> captureots 并且大部分逻辑似乎都在那里。我的计划是克隆 repo 并对其进行精简,直到我保留了基本功能,但效果不佳
  • pryr::where 在不使用 C 的情况下查找名称的环境。
  • 对于那些很可能需要 C 或 C++ 的 r 问题,我们缺少一个标签……我也有标签 C 但有人也删除了它,可能是出于类似的原因。独特的专业知识应该有其独特的标签

标签: r metaprogramming ellipsis


【解决方案1】:

我认为您可以通过向下迭代调用堆栈并从调用中收集未评估的参数并删除“...”来做到这一点,而无需低级语言:

f <- function(...) {
  mc <- as.list(match.call())[-1]
  pf <- 0
  result <- list()
  
  while(TRUE) {
    ind <- length(sys.frames()) - pf - 1
    parent_frame <- if(ind == 0) .GlobalEnv else sys.frames()[[ind]]
    parent_call <- sys.calls()[[length(sys.calls()) - pf]]
    pc_list <- sapply(as.list(parent_call)[-1], 
                      function(x) {
                        if(deparse(x) == "...") NULL else x
                      })
    trim_list <- pc_list[!sapply(pc_list, is.null)]
    for(i in seq_along(trim_list)) {
      trim_list[[i]] <- list(expr = unname(trim_list[[i]]),
                                               env = parent_frame)
    }
    
    result <- c(trim_list, result)
    
    if(identical(parent_frame, .GlobalEnv)) break else pf <- pf + 1
  }
  return(result)
}

这似乎适用于您的示例:

g <- function(...) f(..., b = z)

g(a = x, y)
#> $a
#> $a$expr
#> x
#> 
#> $a$env
#> <environment: R_GlobalEnv>
#> 
#> 
#> [[2]]
#> [[2]]$expr
#> y
#> 
#> [[2]]$env
#> <environment: R_GlobalEnv>
#> 
#> 
#> $b
#> $b$expr
#> z
#> 
#> $b$env
#> <environment: 0x0000024e8d9fcc20>

创建于 2022 年 10 月 23 日,reprex v2.0.2

【讨论】:

    猜你喜欢
    • 2021-04-13
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-08-09
    • 1970-01-01
    相关资源
    最近更新 更多