如果我按如下方式创建一个函数:
what_is_love <- function(f) {
function(...) {
cat('f is', f, '\n')
}
}
并使用lapply
:funs <- lapply(c('love', 'cherry'), what_is_love)
我得到意想不到的输出:
> funs[[1]]()
f is cherry
> funs[[2]]()
f is cherry
但请注意,当您不使用lapply
时,情况并非如此:
> f1 <- what_is_love('love')
> f2 <- what_is_love('cherry')
> f1()
f is love
> f2()
f is cherry
是什么给出了?
我知道可以更全面地写出funs <- lapply(c('love', 'cherry'), what_is_love)
:
params <- c('love', 'cherry')
out <- vector('list', length(params))
for (i in seq_along(params)) {
out[[i]] <- what_is_love(params[[i]])
}
out
但是当我浏览时,我发现两个函数都有自己的环境:
Browse[1]> out[[1]]
function(...) {
cat('f is', f, '\n')
}
<environment: 0x109508478>
Browse[1]> out[[2]]
function(...) {
cat('f is', f, '\n')
}
<environment: 0x1094ff750>
但在每个环境中,f
都是相同的......
Browse[1]> environment(out[[1]])$f
[1] "cherry"
Browse[1]> environment(out[[2]])$f
[1] "cherry"
我知道答案是“懒惰评估”,但我正在寻找更深入的内容...... f
如何在两种环境中重新分配? f
来自哪里?在这个例子中,R懒惰评估是如何工作的?
-
编辑:我知道关于懒惰评估和功能的the other question,但它只是说答案是“懒惰评估”而没有解释懒惰评估实际上是如何工作的。我正在寻求更大的深度。
答案 0 :(得分:16)
当你这样做时
what_is_love <- function(f) {
function(...) {
cat('f is', f, '\n')
}
}
内部函数为f
创建一个封闭空间,但问题是,在您实际使用传递给函数的变量之前,它仍然是一个&#34; promise&#34;并没有实际评估。如果你想&#34;捕获&#34; f
的当前值,那么你需要强制评估承诺;您可以使用此force()
函数。
what_is_love <- function(f) {
force(f)
function(...) {
cat('f is', f, '\n')
}
}
funs <- lapply(c('love', 'cherry'), what_is_love)
funs[[1]]()
# f is love
funs[[2]]()
# f is cherry
如果没有force()
,f
仍然是列表中两个功能的承诺。在调用函数之前,并且在调用函数时,不会对它进行求值,该函数将promise计算为f
的最后一个已知值,即&#34; cherry。&#34;
正如@MartinMorgran所指出的,这种行为在R 3.2.0中发生了变化。来自release notes
高阶函数,例如apply函数和Reduce() 现在强制参数为他们应用的函数 消除懒惰评估与之间不良的相互作用 闭包中的变量捕获。这解决了PR#16093。