在 for 循环中封闭变量 [英] Enclosing variables within for loop
问题描述
所以考虑下面的代码块,它不像大多数人所期望的那样工作
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屋!