【发布时间】:2014-11-21 18:21:58
【问题描述】:
因此,请考虑以下代码块,它不像大多数人所期望的那样工作
#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 循环似乎不会为每次迭代创建不同的环境。
sapply(f, environment)
# [[1]]
# <environment: R_GlobalEnv>
# [[2]]
# <environment: R_GlobalEnv>
# [[3]]
# <environment: R_GlobalEnv>
所以我虽然可以使用local() 和force() 来捕获i 值
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]])))。将此与
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 的当前值捕获到当前环境中。它在以下情况下很有用
#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 是作为参数/承诺传递的,但这不能是 for 循环中发生的事情。
所以我的问题是:是否可以在没有local() 和变量重命名的情况下创建这个函数列表?是否有比force() 更合适的函数将变量的值从父框架捕获到本地/当前环境中?
【问题讨论】:
-
您能否澄清一下为什么您对变量重命名不满意我的意思是解决方案:
f[[i]] <- local({ai<-i; function(x) a[ai]+x})? -
与其说让我不开心,倒不如说这是唯一的方法,我不明白为什么这是唯一的方法。为什么一定要改名?有没有办法进行设置,这样我就不必重命名(我只想像在
lapply版本中那样获取具有相同名称的变量的副本)。这更有意义吗?
标签: r for-loop lazy-evaluation