在 for 循环中封闭变量 [英] Enclosing variables within for loop

查看:40
本文介绍了在 for 循环中封闭变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以考虑下面的代码块,它不像大多数人所期望的那样工作

So consider the following chunk of code which does not work as most people might expect it to

#cartoon example
a <- c(3,7,11)
f <- list()

#manual initialization
f[[1]]<-function(x) a[1]+x
f[[2]]<-function(x) a[2]+x
f[[3]]<-function(x) a[3]+x

#desired result for the rest of the examples
f[[1]](1)
# [1] 4
f[[3]](1)
# [1] 12

#attempted automation
for(i in 1:3) {
   f[[i]] <- function(x) a[i]+x
}

f[[1]](1)
# [1] 12
f[[3]](1)
# [1] 12

请注意,我们尝试自动化"后两次都得到 12.当然,问题是 i 没有包含在函数的私有环境中.所有函数在全局环境中都引用相同的 i(它只能有一个值),因为 for 循环似乎不会为每次迭代创建不同的环境.

Note that we get 12 both times after we attempt to "automate". The problem is, of course, that i isn't being enclosed in the function's private environment. All the functions refer to the same i in the global environment (which can only have one value) since a for loop does not seem to create different environment for each iteration.

sapply(f, environment)
# [[1]]
# <environment: R_GlobalEnv>
# [[2]]
# <environment: R_GlobalEnv>
# [[3]]
# <environment: R_GlobalEnv>

所以我虽然可以使用 local()force() 来捕获 i 值>

So I though I could get around with with the use of local() and force() to capture the i value

for(i in 1:3) {
   f[[i]] <- local({force(i); function(x) a[i]+x})
}

f[[1]](1)
# [1] 12
f[[3]](1)
# [1] 12

但这仍然不起作用.我可以看到它们都有不同的环境(通过 sapply(f, environment))但是它们似乎是空的(ls.str(envir=environment(f[[1]]))).将此与

but this still doesn't work. I can see they all have different environments (via sapply(f, environment)) however they appear to be empty (ls.str(envir=environment(f[[1]]))). Compare this to

for(i in 1:3) {
   f[[i]] <- local({ai<-i; function(x) a[ai]+x})
}

f[[1]](1)
# [1] 4
f[[3]](1)
# [1] 12

ls.str(envir=environment(f[[1]]))
# ai :  int 1
ls.str(envir=environment(f[[3]]))
# ai :  int 3

很明显 force() 没有像我预期的那样工作.我假设它会将 i 的当前值捕获到当前环境中.这在

So clearly the force() isn't working like I was expecting. I was assuming it would capture the current value of i into the current environment. It is useful in cases like

#bad
f <- lapply(1:3, function(i) function(x) a[i]+x)
#good
f <- lapply(1:3, function(i) {force(i); function(x) a[i]+x})

其中 i 作为参数/promise 传递,但这一定不是 for 循环中发生的事情.

where i is passed as a parameter/promise, but this must not be what's happening in the for-loop.

所以我的问题是:是否可以在没有 local() 和变量重命名的情况下创建这个函数列表?是否有比 force() 更合适的函数可以将变量的值从父框架捕获到本地/当前环境中?

So my question is: is possible to create this list of functions without local() and variable renaming? Is there a more appropriate function than force() that will capture the value of a variable from a parent frame into the local/current environment?

推荐答案

这不是一个完整的答案,部分原因是我不确定问题到底是什么(尽管我觉得它很有趣!).

This isn't a complete answer, partly because I'm not sure exactly what the question is (even though I found it quite interesting!).

相反,我将仅展示两个有效的替代 for 循环.他们帮助澄清了我心中的问题(特别是帮助我第一次理解为什么 force() 在调用 lapply() 时会做任何事情>).我希望他们也能帮助你.

Instead, I'll just present two alternative for-loops that do work. They've helped clarify the issues in my mind (in particular by helping me to understand for the first time why force() does anything at all in a call to lapply()). I hope they'll help you as well.

首先,这里有一个更接近于正确函数 lapply() 调用的方法,它的工作原理与它相同:

First, here is one that's a much closer equivalent of your properly function lapply() call, and which works for the same reason that it does:

a <- c(3,7,11)
f <- list()

## `for` loop equivalent of:
## f <- lapply(1:3, function(i) {force(i); function(x) a[i]+x})
for(i in 1:3) {
    f[[i]] <- {X <- function(i) {force(i); function(x) a[i]+x}; X(i)}
}
f[[1]](1)
# [1] 4

其次,这里有一个确实使用了 local() 但没有(严格地或字面地说)重命名 i.但是,它确实通过将它的一个副本添加到本地环境来重新调整"它的范围.从某种意义上说,它与您的 for 循环只是微不足道的不同,但是通过将注意力集中在 i 的范围而不是它的名称上,我认为它有助于阐明关于您问题背后的实际问题.

Second, here is one that does use local() but doesn't (strictly- or literally-speaking) rename i. It does, though, "rescope" it, by adding a copy of it to the local environment. In one sense, it's only trivially different from your functioning for-loop, but by focusing attention on i's scope, rather than its name, I think it helps shed light on the real issues underlying your question.

a <- c(3,7,11)
f <- list()

for(i in 1:3) {
   f[[i]] <- local({i<-i; function(x) a[i]+x})
}
f[[1]](1)
# [1] 4

这篇关于在 for 循环中封闭变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆