2012-04-04 8 views
5

Sto tentando di utilizzare una serie di chiamate lapply per creare un elenco di funzioni elaborate, che idealmente nell'ultima chiamata lapply restituisce il valore finale desiderato. Il currying funziona, ma lapply sembra applicare sempre l'ultimo elemento nell'elenco dopo la seconda applicazione.Perché i valori delle variabili nelle chiusure vengono persi dopo aver ripetutamente chiamato lapply?

Esempio:

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 
} 

Questo funziona come previsto:

# 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 

La prossima lapply di curry "storpia il campo di applicazione":

# 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 

Non sembra come un risultato della funzione curry o rcurry. L'uso della funzione Curry di roxygen fa la stessa cosa. creando curry.a chiudendo sopra o usando curry.a <- list(curry(myadd, 10), curry(myadd, 1000)) anche i risultati sono gli stessi.

E, naturalmente, il curry finale:

# 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 

cosa sta succedendo qui?

+2

'' lapply' valuta FUN' in un nuovo ambiente. Penso che abbia qualcosa a che fare con questo. –

+0

Penso che la risposta sia la stessa della risposta di Tommy a http://stackoverflow.com/questions/9950144/access-lapply-index-names-inside-fun/9950734#comment12707459_9950734 –

+0

Joshua è caldo, kohske lo inchioda. Grazie a tutti. –

risposta

2

fn in curry non viene valutato nell'ambito della funzione e quindi è promise. Se force allora si può ottenere ciò che vi aspettate:

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

poi,

> 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 

più internamente, lapply genera una variabile locale X che viene definito da ogni chiamata della funzione. Se X non viene valutato in ciascuna funzione quando si chiama lapply, X è promettente. Dopo aver chiamato lapply, X in tutte le chiamate di funzione da lapply restituisce lo stesso valore (vale a dire, ultimo). Così lapply è simile con:

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

poi,

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

Occhio di toro al 100%. Grazie! In realtà ho pensato che la chiusura fosse la promessa, quindi ho fatto 'closure <- function (...) {do.call (fn, append (arglist, list (...))}; force (closure); return closure' Certo, questo non ha funzionato. –

Problemi correlati