微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 do.call

如何解决在 do.call

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

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

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

b <- 1
Foo(2)
# 3

真正的函数将接受一个参数列表,所以我使用的是 do call,很简单:

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

local 块(或 test_that 块)中运行它这不符合我想要的方式(无论哪种方式)。

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

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

我尝试使用 do.callenvironment() 方法parent.env()quote = TRUE、...)提供不同的环境,但没有使用但无济于事。

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

解决方法

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())

5) 另一种方法是使用 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 将语句注入 Foo 中,然后将其删除。

trace

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

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

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

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
,

您应该使用复杂的赋值运算符 <<-,因为您想在函数执行环境的父环境中更改 b 的值:

library(rlang)

local({
    b <<- 3
    print(Foo(2))
    print(do.call(Foo,list(a = 2)))
    list(env = env_parent(current_env()))  # I added this so it becomes clear that this is the child of Global environment. You can omit it if you like. 
  })

[1] 5
[1] 5
$env
<environment: R_GlobalEnv>

我再次阅读了您的描述,看到您希望在 local 的本地环境中评估您的函数。所以就像我朋友建议的那样:

local({
    b <- 3
    print(Foo(2))
    print(do.call(Foo,list(a = 2)))
    
  },envir = current_env())

[1] 5
[1] 5

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?