r - 查找调用的 ...(点)参数的原始环境

标签 r rlang

我希望能够找到 ... 所在的环境(点)调用的参数起源。

设想

例如,考虑一个函数

foo <- function(x, ...) {
  # do something
}

我们想要一个函数env_dots() , 我们从 foo() 中调用,找到 ... 的原始环境调用foo() , 即使调用 foo()嵌套很深。也就是说,如果我们定义
foo <- function(x, ...) {
  # find the originating environment of '...'
  env <- env_dots()

  # do something
}

并嵌套调用 foo ,像这样,
baz <- function(...) {
  a <- "You found the dots"
  bar(1, 2)
}
bar <- function(...)
  foo(...)

然后调用baz()应该返回 ... 所在的环境在对 foo(...) 的(嵌套)调用中起源:这是调用 bar(1, 2) 的环境已制作,因为 2 (但不是 1 )被传递给 foo 的点.特别是,我们应该得到
baz()$a
#> [1] "You found the dots"
env_dots() 的幼稚实现

更新 env_dots() ,如此处所定义的,一般不会起作用,因为最终的 ...可以由在调用堆栈的多个级别调用的参数填充。

这是 env_dots() 的一种可能性:
# mc: match.call() of function from which env_dots() is called
env_dots <- function(mc) {
  # Return NULL if initial call invokes no dots
  if (!rlang::has_name(mc, "...")) return(NULL)

  # Otherwise, climb the call stack until the dots origin is found
  stack <- rlang::call_stack()[-1]
  l <- length(stack)
  i <- 1
  while (i <= l && has_dots(stack[[i]]$expr)) i <- i + 1
  # return NULL if no dots invoked
  if (i <= l) stack[[i + 1]]$env else NULL
}

# Does a call have dots?
has_dots <- function(x) {
  if (is.null(x))
    return(FALSE)
  args <- rlang::lang_tail(x)
  any(vapply(args, identical, logical(1), y = quote(...)))
}

这似乎有效:与
foo <- function(x, ...)
  env_dots(match.call(expand.dots = FALSE))

我们得到
baz()$a
#> [1] "You found the dots"

bar(1, 2)  # 2 gets passed down to the dots of foo()
#> <environment: R_GlobalEnv>

bar(1)     # foo() captures no dots
#> NULL

问题
env_dots()的上述实现效率不是很高。
  • 有没有更巧妙的实现方式env_dots() rlang 和/或 基础 R ?
  • 如何移动 match.call()env_dots() 内调用?match.call(sys.function(-1), call = sys.call(-1), expand.dots = FALSE)确实会起作用。

  • 备注 — 无法从 rlang::quos(...) 推断点的起源环境, 因为某些 quosures 不会被赋予调用环境(例如,当表达式是文字对象时)。

    最佳答案

    很抱歉提出一个老问题,但我不确定所需的行为是否明确。 ...不是一个单一的表达式;这是一个表达式列表。如果是 rlang quosures,每个表达式都有自己的环境。那么list的环境应该是怎样的呢?

    此外,...列表本身可以修改。考虑以下示例,其中 g拿它的... , 在它前面加上一个(未计算的)表达式 x+3并将其传递给 f .

    f <- function(...) {rlang::enquos( ... )}
    
    g <- function(...) {
      a <- rlang::quo( x + 3 )
      l <- rlang::list2( a, ... )
      f(!!!l)
    }
    
    b <- rlang::quo( 5 * y )
    
    g( b, 10 )
    # [[1]]
    # <quosure>
    #   expr: ^x + 3
    #   env:  0x7ffd1eca16f0
    
    # [[2]]
    # <quosure>
    #   expr: ^5 * y
    #   env:  global
    
    # [[3]]
    # <quosure>
    #   expr: ^10
    #   env:  empty
    

    请注意,将其转换为 f 的三个 quosures 中的每一个有自己的环境。 (正如您在问题中指出的那样,10 之类的文字有一个空环境。这是因为值是相同的,与它在哪个环境中进行评估无关。)

    鉴于这种情况,假设的 env_dots() 应该是什么?在 f() 内部调用时返回?

    关于r - 查找调用的 ...(点)参数的原始环境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44773281/

    相关文章:

    r - env_parent() : different results when using default argument or when passing explicitly default argument

    R不显示y值但保留y轴

    r - 如何在函数内部/内部使用?

    r - 在不同的环境中调用 R 函数

    r - 如何引用包含引用调用的表达式并取消引用其中的字符串?

    r - 如何在函数内部使用 rlang::as_string()?

    r - rlang::flatten() 的基本等价物是什么?

    r - data.table 在选定的列中重新编码

    替换 R 中向量中多次出现的值

    r - 在 R 中将列表拆分为单独的数据框