【问题标题】:function environment within lapply looplapply 循环内的函数环境
【发布时间】:2018-01-15 18:35:03
【问题描述】:

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

我的玩具示例非常简单:我有一个函数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的外循环......为什么?

【问题讨论】:

  • 好问题。 ?lapply 上的唯一信息似乎是,“如果 expr 是一个函数调用,请注意关于它在何处被评估的假设”。
  • 感谢@RemkoDuursma 的链接!

标签: r function lapply environment


【解决方案1】:

我相信这是因为函数 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

【讨论】:

    【解决方案2】:

    有 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

    • 执行(包含在调用环境中):动态创建,并包含...我什至不确定在哪里,但是当沿着封闭环境链向上时,应该有@的执行环境987654332@

    • 呼叫:相同,不太确定...但没关系

    但是:
    (可能)与直觉相反,通过向上“调用堆栈”AKA 动态范围(即:foo 的 exec env,(然后可能是一些中间环境),然后是 lapply 的 exec env(我们会在其中找到 i &lt;- 42),然后是 .GlobalEnv),但直接在 foo 的封闭环境中 AKA 词法作用域,然后是其封闭环境的链,从而绕过了lapply的执行环境,从而找不到i,即使上面明确声明了...

    【讨论】:

      猜你喜欢
      • 2015-10-12
      • 1970-01-01
      • 2015-10-11
      • 2021-02-16
      • 2014-07-16
      • 1970-01-01
      • 2021-11-14
      • 2013-09-09
      相关资源
      最近更新 更多