dir*_*ugh 5 closures scope r currying lapply
我正在尝试使用一系列lapply调用来构建curried函数列表,理想情况下,在最后一次lapply调用时,返回最终的期望值.currying工作,但lapply似乎总是应用第二个应用程序后列表中的最后一个元素.
例:
curry <- function(fn, ...) {
arglist <- list(...)
function(...) {
do.call(fn, append(arglist, list(...)))
}
}
# rcurry is used only to init the first lapply.
rcurry <- function(v1, fn, ...) {
arglist <- append(list(v1), list(...))
function(...) {
do.call(fn, append(arglist, list(...)))
}
}
myadd <- function(a,b,c) {
a+b+c
}
Run Code Online (Sandbox Code Playgroud)
这按预期工作:
# you can achieve the same by closure:
# curry.a <- lapply(c(10, 1000), FUN = function(a) { curry(myadd, a) })
curry.a <- lapply(list(10, 1000), rcurry, myadd)
curry.a[[1]](1,2)
curry.a[[2]](1,2)
# > [1] 13
# > [1] 1003
Run Code Online (Sandbox Code Playgroud)
接下来lapply的curry"轧液范围":
# this does give the desired output:
# curry.a.b <- list(curry(curry.a[[1]], 1), curry(curry.a[[2]], 1))
curry.a.b <- lapply(curry.a, curry, 1)
curry.a.b[[1]](2)
curry.a.b[[2]](2)
# > [1] 1003
# > [1] 1003
Run Code Online (Sandbox Code Playgroud)
它似乎不是curry或rcurry函数的结果.使用roxygen的Curry函数做同样的事情.curry.a通过上面的闭包创建或使用curry.a <- list(curry(myadd, 10), curry(myadd, 1000))也会产生相同的结果.
当然最后的咖喱:
# it doesn't work if you re-define this:
# curry.a.b <- list(curry(curry.a[[1]], 1), curry(curry.a[[2]], 2))
curry.a.b.c <- lapply(curry.a.b, curry, 2)
lapply(curry.a.b.c, do.call, list())
# > [1] 1003
# > [1] 1003
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?
fnincurry不在函数范围内求值,因此它是promise。如果你force这样做,那么你可以得到你所期望的:
curry <- function(fn, ...) {
force(fn)
arglist <- list(...)
function(...) {
do.call(fn, append(arglist, list(...)))
}
}
Run Code Online (Sandbox Code Playgroud)
然后,
> curry.a.b <- lapply(curry.a, curry, 1)
> curry.a.b[[1]](2)
[1] 13
> curry.a.b[[2]](2)
[1] 1003
>
> curry.a.b.c <- lapply(curry.a.b, curry, 2)
> lapply(curry.a.b.c, do.call, list())
[[1]]
[1] 13
[[2]]
[1] 1003
Run Code Online (Sandbox Code Playgroud)
更内部的是,生成一个由每次函数调用引用的lapply局部变量。X如果X在调用 , 时不在每个函数中求值lapply,X则为 Promise。调用后lapply,X在所有函数调用中lapply返回相同(即最后一个)值。因此lapply与以下类似:
f0 <- function(i) function() i
f1 <- function(i) {force(i); function() i}
f <- local({
r0 <- list()
r1 <- list()
for (i in 1:2) {
r0[[i]] <- f0(i)
r1[[i]] <- f1(i)
}
list(r0 = r0, r1 = r1)
})
Run Code Online (Sandbox Code Playgroud)
然后,
> f$r0[[1]]()
[1] 2
> f$r1[[1]]()
[1] 1
> f$r0[[2]]()
[1] 2
> f$r1[[2]]()
[1] 2
Run Code Online (Sandbox Code Playgroud)