lapply 循环内的函数环境

function environment within lapply loop

所以我遇到了这个与存在于不同环境中的变量有关的问题,这让我很困惑,因为它不符合我对函数如何查找各种对象的理解。

我的玩具示例非常简单:我有一个函数 foo 接受一个参数 jfoo 存在于带有参数 'i' 的 lapply 循环的函数中。现在,i 显然存在于 lapply 环境中(而不是在全局环境中)。在 lapply 函数中调用时 foo 很难找到 i 并抛出错误:

foo <- function(j){
 message('foo env: exists(j) ', exists('j'))
 message('foo env: exists(i) ', exists('i'))
 i
}

env.g <- environment()
invisible(lapply(1, FUN = function(i){
  message('global env: exists(i) ', exists('i', envir = env.g))
  message('lapply env: exists(i) ', exists('i'))
  message(' ')
  j <- i + 1

  foo(j)
   }
  ))

#global env: exists(i) FALSE
#lapply env: exists(i) TRUE

#foo env: exists(j) TRUE
#foo env: exists(i) FALSE
#Error in foo(j) : object 'i' not found

另一方面,当 i 存在于全局环境中时,foo 可以接受:

i <- 10
foo()
#foo env: exists(j) TRUE
#foo env: exists(i) TRUE
#[1] 10

所以我之前的理解是,如果一个函数在它自己的环境中没有看到一个变量,它会转到下一个(lapply 在我的第一个例子和全局环境中。在我的第二个) , 直到找到为止。但是,它显然没有进入上面 lapply 的外循环...为什么?

我认为这是因为函数 foo() 是在定义它的环境中求值的。在您的示例中,foo() 是在全局环境中定义的,因此 i 不在范围内。如果您在匿名函数中定义 foo(),则 i 似乎被正确评估。

env.g <- environment()
invisible(lapply(1, FUN = function(i){
  message('global env: exists(i) ', exists('i', envir = env.g))
  message('lapply env: exists(i) ', exists('i'))
  message(' ')
  j <- i + 1

  foo <- function(j){
   message('foo env: exists(j) ', exists('j'))
   message('foo env: exists(i) ', exists('i'))
   i
  }

  foo(j)
   }
  ))

#global env: exists(i) FALSE
#lapply env: exists(i) TRUE

#foo env: exists(j) TRUE
#foo env: exists(i) TRUE

有 4 种类型的环境与函数关联。

当你运行:

rm(i)
lapply(1, foo)

甚至:

rm(i)
lapply(1, function(x) {
  i <- 42
  foo(x)
})

情况是:

lapply:

  • 封闭环境:namespace:base

  • 绑定环境:package:base

  • 执行环境:即时创建,并包含在.GlobalEnv

  • 调用环境:.GlobalEnv

foo:

  • 封闭(定义的地方):.GlobalEnv

  • 绑定(其中名称foo是):.GlobalEnv

  • 执行(包含在 Calling env 中):动态创建,并包含...我什至不确定在哪里,但是在封闭环境链中向上移动时,应该有lapply

  • 的执行环境
  • 打电话:一样,不太确定...不过应该没关系

但是:
(可能)与直觉相反,通过 "call stack" AKA dynamic scoping(即:exec env foo,(然后可能是一些中间环境),然后是 lapply 的 exec env(我们会找到 i <- 42),然后是 .GlobalEnv),但直接在封闭环境中foo AKA 词法范围,然后是其封闭环境的链,从而绕过了 lapply 的执行环境,因此没有找到 i,即使它在上面明确声明...