I'm attempting to use a series of lapply
calls to build a list of curried functions, which ideally at the last lapply
call, returns the final desired value. The currying works, but lapply
seems to always applies the last element in the list after the second application.
Example:
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
}
This works as expected:
# 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
The next lapply
of curry
"mangles the scope":
# 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
It doesn't seem like a result of the curry
or rcurry
function. Using roxygen
's Curry
function does the same thing. creating curry.a
by closure above or using curry.a <- list(curry(myadd, 10), curry(myadd, 1000))
also results the same.
And of course the final curry:
# 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
What's going on here?
fn
in curry
is not evaluated in the scope of function and hence it is promise
.
If you force
it then you can get what you expect:
curry <- function(fn, ...) {
force(fn)
arglist <- list(...)
function(...) {
do.call(fn, append(arglist, list(...)))
}
}
then,
> 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
More internally, lapply
generates a local variable X
that is referred by each call of function. If X
is not evaluated in each function when calling the lapply
, X
is promise. After calling lapply
, X
in all function call from lapply
returns same (i.e., last) value. So lapply
is similar with:
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)
})
then,
> f$r0[[1]]()
[1] 2
> f$r1[[1]]()
[1] 1
> f$r0[[2]]()
[1] 2
> f$r1[[2]]()
[1] 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With