R指定函数环境

16

我有一个关于R语言中函数环境的问题。

我知道每次在R中调用函数时,都会创建一个新的环境E来执行函数体。E的父链接指向创建函数的环境。

我的问题是:是否可以以某种方式指定环境E?也就是说,能否提供一个特定的环境来执行函数?


2
“environment(fun) <- value” 在 ?environment 中被描述,这种方式有什么问题吗? - Joshua Ulrich
1
你可以在全局环境以外的环境中评估函数调用,但这仍将生成一个新环境函数内,但现在该环境的父级将是您在其中进行评估而不是全局环境。 这样可以吗? 如果可以,请参阅?with?eval,后者是由with()使用的较低级别函数。 - Gavin Simpson
3
您能否更改函数的功能,以便在指定的环境中设置所需的调用,然后对其进行评估。然后您将拥有GlobalEnv > fun执行env > eval call in指定的env。我认为您无法阻止R在调用函数时创建新的环境,但是您可以修改函数体以在指定的环境中执行其工作,而不是R创建的环境(当然,该环境仍将存在和被创建,您只是在之后更改环境)。 - Gavin Simpson
3
请具体说明您想要更改执行函数的环境中的哪些内容,是添加某个对象还是更改环境变量?请提供更具体的细节。 - Paul Hiemstra
1
@amonk(悬赏的赞助商):请描述您期望的限制,例如:是否允许更改受影响函数的函数体,是否允许包装函数,是否允许修改执行函数的每个代码点,您是否还想修改来自软件包的函数... - R Yoda
显示剩余3条评论
3个回答

19

函数具有一个环境,可以从函数外部更改该环境,但不能在函数内部更改。环境是函数的属性,可以使用 environment() 进行检索/设置。函数最多只有一个环境,但可以复制该函数并带有不同的环境。

让我们设置一些带有 x 值的环境。

x <- 0
a <- new.env(); a$x <- 5
b <- new.env(); b$x <- 10

同时还有一个函数 foo,它使用了环境中的变量 x

Translated:

and a function foo that uses x from the environment


Translated:

同时还有一个函数 foo,它使用了环境中的变量 x

foo <- function(a) {
    a + x
}
foo(1)
# [1] 1

现在我们可以编写一个辅助函数,用它来调用任何环境中的函数。

with_env <- function(f, e=parent.frame()) {
    stopifnot(is.function(f))
    environment(f) <- e
    f
}

实际上,这将返回一个具有不同环境分配的新函数(如果未指定,则使用调用环境),我们可以通过传递参数来调用该函数。观察

with_env(foo, a)(1)
# [1] 6
with_env(foo, b)(1)
# [1] 11
foo(1)
# [1] 1

5
这是另一种解决问题的方法,直接从http://adv-r.had.co.nz/Functional-programming.html中获取。
考虑下面的代码。
new_counter <- function() {
  i <- 0
  function() {
    i <<- i + 1
    i
  }
}

(更新以改善准确性) 外部函数创建了一个环境,该环境被保存为一个变量。调用这个变量(即一个函数)实际上是调用内部函数,该函数更新与外部函数关联的环境。(我不想直接复制Wickham关于此问题的整个部分,但我强烈建议任何有兴趣的人阅读标题为“可变状态”的部分。我认为你可以做得比这更高级。例如,这是一种带有重置选项的修改:)
new_counter <- function() {
  i <- 0
  function(reset = FALSE) {
    if(reset) i <<- 0
    i <<- i + 1
    i
  }
}

counter_one <- new_counter()
counter_one()
counter_one()
counter_two <- new_counter()
counter_two()
counter_two()
counter_one(reset = TRUE)

2
那很糟糕!不过我还是有点喜欢它。 - amonk

2

我不确定我完全理解问题的目标。但是可以设置函数执行的环境,修改该环境中的对象,然后从全局环境引用它们。这里有一个说明性的例子,但我不知道是否回答了提问者的问题:

e <- new.env()
e$a <- TRUE
testFun <- function(){
  print(a)
}
testFun()

结果为:打印(a)时出错:未找到对象'a'

testFun2 <- function(){
  e$a <- !(a) 
  print(a)
}
environment(testFun2) <- e
testFun2()

返回值:FALSE
e$a 

返回值:FALSE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接