R:我可以让函数的执行环境永久化吗?

R: Could I make the execution environment of a function permanent?

我正在研究 R 环境,但在阅读 Hadley Wickham 的“Advanced R”一书时遇到了问题。是否可以让一个函数的执行环境永久化?

我会尝试解释我的问题的原因。

当 Wickham 解释函数的执行环境如何工作时,显示了以下示例:

j <- function() {
    if (!exists("a")) {
         a <- 1
    } else {
         a <- a + 1
    }
    print(a)
}
j()

我明白为什么每次调用函数 j 时返回值都是 1。 在文本的另一部分,他说:

When you create a function inside another function, the enclosing environment of the child function is the execution environment of the parent, and the execution environment is no longer ephemeral.

所以我想创建以下函数:

j <- function() {
    if (!exists("a")) {
        a <- 1
    } else {
        a <- a + 1
    }
    print(a)
    g <- function() {}
    g()
}
j()

但是返回值一直是1,估计是因为执行环境每次都在继续被破坏。 “不再短暂”是什么意思?

函数内的永久环境称为“闭包”。这里有一个玩具示例来演示这一点。检查一下,然后相应地修改您的代码。

closure <- function(j) {
  i <- 1
  function(x) {
    i <<- i + 1
    j * i + x
  }
}

i <- 12345
instance <- closure(11)

instance(3)
#[1] 25

instance(3)
#[1] 36

instance(3)
#[1] 47

otherObj <- closure(2)
otherObj(3)
#[1] 7

instance(2)
#[1] 57

根据本书,还可以使用函数工厂结构(创建另一个函数的函数)来捕获第一个函数的临时执行环境。以下示例只是我们如何捕获它的一种简单方法:

library(rlang)

j <- function() {
  print(current_env())
  a <- 1
  k <- function() {
    if (!exists("a")) {
      a <- 1
    } else {
      a <- a + 1
    }
    print(a)
  }
}

plus <- j()

> plus <- j()
<environment: 0x000001ca98bc1598>

现在无论你使用函数plus多少次,它的环境永远是第一个函数当时的执行环境:

library(rlang)

env_print(plus)
<environment: 000001CA98BC1598>
parent: <environment: global>
bindings:
 * k: <fn>
 * a: <dbl>

plus()
[1] 2

env_print(plus)
<environment: 000001CA98BC1598>
parent: <environment: global>
bindings:
 * k: <fn>
 * a: <dbl>

我希望这在一定程度上回答了您的问题,但可能还有更好的答案。