r - 在 do.call 调用的函数中查找局部变量

标签 r do.call

我有一个函数,该函数应该根据调用它的环境使用一个值:

Foo <- function(a) {
  return(a + b)
}

在全局环境中我现在可以简单地做

b <- 1
Foo(2)
# 3

真正的函数将采用参数列表,因此我使用 do call,很简单:

do.call(Foo, list(a = 2)
# 3

local block (或 test_that block )中运行它,这不会按照我想要的方式工作(无论哪种方式)。

local({
  b <- 3
  print(Foo(2))
  print(do.call(Foo, list(a = 2)))
})
# [1] 3
# [1] 3

这将返回 3,我想要 5。如果我没有定义或删除全局 b,该函数将会失败,因为它找不到该符号。

我尝试为 do.call 方法提供不同的环境(environment()parent.env(),...)使用 quote = TRUE 和不使用但无济于事。

有没有办法强制 Foo 通过将其作为环境传递来查找本地 block 中的变量?

最佳答案

1) 由于 b 没有在 Foo 中定义,因此 Foo 将在定义 Foo 的环境中查找 b,而不是在调用它的环境中。

您可以重新定义 Foo 的环境。这将创建 Foo 的副本,以便在本地环境中查找其中的自由变量。没有使用任何包。

local({
    b <- 3
    environment(Foo) <- environment()
    print(Foo(2))
    print(do.call(Foo, list(a = 2)))
    
})
## [1] 5
## [1] 5

2) 如果可以修改 Foo,那么其他可能性是通过传递 b 作为附加参数或传递环境作为附加参数来修改它,并让 Foo 在该环境中评估 b。

Foo2 <- function(a, b) {
  return(a + b)
}
local({
    b <- 3
    print(Foo2(2, b))
    print(do.call(Foo2, list(a = 2, b = b)))
})
## [1] 5
## [1] 5

3)

Foo3 <- function(a, envir = parent.frame()) {
  return(a + envir$b)
}
local({
    b <- 3
    print(Foo3(2))
    print(do.call(Foo3, list(a = 2)))
    
  })
## [1] 5
## [1] 5

4) 上述内容的一个变体,仅涉及修改 Foo 的签名而不是其主体,如下所示(或使用 get("b",parent.frame()) (如果您想允许它也查看父框架的祖先)。

Foo4 <- function(a, b = parent.frame()$b) {
  return(a + b)
}
local({
    b <- 3
    print(Foo4(2))
    print(do.call(Foo4, list(a = 2)))
  })
## [1] 5
## [1] 5

5) 另一种方法是使用 trace 将语句注入(inject) Foo,然后将其删除。

local({
  b <- 3
  on.exit(untrace(Foo))
  trace(Foo, bquote(b <- .(b)), print = FALSE)
  print(Foo(2))
  print(do.call(Foo, list(a = 2)))
})
## [1] 5
## [1] 5

6) 如果我们将 Foo 的主体包装在 eval.parent(substitute({...})) 中,这将有效地将其注入(inject)到调用者中,使其能够访问 b。另请参阅从 R News 1/3 第 11 页开始的 Thomas Lumley 文章.

Foo6 <- function(a) eval.parent(substitute({
  return(a + b)
}))
local({
  b <- 3
  print(Foo6(2))
  print(do.call(Foo6, list(a = 2)))
})
## [1] 5
## [1] 5

7) 这实际上与引擎盖下的 (6) 相同,只是它包裹得很好。这是这里唯一使用包的一个。

library(gtools)

Foo7 <- defmacro(a, expr = {
  return(a + b)
})
local({
  b <- 3
  print(Foo7(2))
  print(do.call(Foo7, list(a = 2)))
})
## [1] 5
## [1] 5

关于r - 在 do.call 调用的函数中查找局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66895588/

相关文章:

r - 如何检查 data.table 各行中的值是否相同

r - do.call 强制在 rlang 的整洁评估之前评估参数

R.do.call函数返回多

r - 将函数应用于 R 中嵌套列表的某些元素

r - data.table 的 do.call rbind 取决于 NA 的位置

r - 将嵌套列表转换为数据框

r - 如何导入带有空白单元格的 csv

r - 发布 R 包版本后,我应该如何处理 CRAN-SUBMISSION 文件

r - 选择要在 data.table 中保留/删除的组

R Shiny 应用程序可保存输入以供以后使用