2012-04-04 31 views
5

Tôi đang cố gắng sử dụng một loạt các cuộc gọi lapply để xây dựng danh sách các hàm được thu thập, lý tưởng nhất là cuộc gọi lapply cuối cùng, trả về giá trị mong muốn cuối cùng. Các công trình currying, nhưng lapply dường như luôn luôn áp dụng phần tử cuối cùng trong danh sách sau ứng dụng thứ hai.Tại sao các giá trị biến trong đóng cửa bị mất sau khi liên tục gọi điện thoại một cách lúng túng?

Ví dụ:

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 
} 

này hoạt động như mong đợi:

# 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 

Tiếp theo lapply của curry "mangles phạm vi":

# 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 

Nó không có vẻ giống như một kết quả của hàm curry hoặc rcurry. Việc sử dụng chức năng Curry của roxygen cũng giống như vậy. tạo curry.a bằng cách đóng cửa ở trên hoặc sử dụng curry.a <- list(curry(myadd, 10), curry(myadd, 1000)) cũng cho kết quả tương tự.

Và dĩ nhiên là cà ri thức:

# 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 

gì đang xảy ra ở đây?

+2

'lapply' đánh giá' FUN' trong một môi trường mới. Tôi nghĩ rằng có một cái gì đó để làm với nó. –

+0

Tôi nghĩ câu trả lời giống như câu trả lời của Tommy đối với http://stackoverflow.com/questions/9950144/access-lapply-index-names-inside-fun/9950734#comment12707459_9950734 –

+0

Joshua ấm áp, kohske làm móng nó. Cảm ơn tất cả. –

Trả lời

2

fn trong curry không được đánh giá trong phạm vi chức năng và do đó nó là promise. Nếu bạn force nó thì bạn có thể có được những gì bạn mong đợi:

curry <- function(fn, ...) { 
    force(fn) 
    arglist <- list(...) 
    function(...) { 
    do.call(fn, append(arglist, list(...))) 
    } 
} 

sau đó,

> 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 nội bộ, lapply tạo ra một biến địa phương X được giới thiệu bởi mỗi cuộc gọi chức năng. Nếu X không được đánh giá trong mỗi chức năng khi gọi số lapply, X là lời hứa. Sau khi gọi lapply, X trong tất cả cuộc gọi chức năng từ lapply trả về cùng giá trị (ví dụ: cuối cùng). Vì vậy lapply là tương tự với:

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) 
}) 

sau đó,

> f$r0[[1]]() 
[1] 2 
> f$r1[[1]]() 
[1] 1 
> f$r0[[2]]() 
[1] 2 
> f$r1[[2]]() 
[1] 2 
+0

100% mắt Bulls. Cảm ơn bạn! Tôi thực sự nghĩ rằng đóng cửa là lời hứa, vì vậy tôi đã 'đóng cửa <- chức năng (...) {do.call (fn, append (arglist, list (...))}; lực lượng (đóng cửa); return closure' Tất nhiên, điều đó không hiệu quả. –