2013-04-01 5 views
13

Quando provo a creare un elenco di funzioni simili usando lapply, trovo che tutte le funzioni nell'elenco sono identiche e uguali a ciò che dovrebbe essere l'elemento finale.Restituisce le funzioni anonime da lapply - cosa sta andando male?

Si consideri il seguente:

pow <- function(x,y) x^y 
pl <- lapply(1:3,function(y) function(x) pow(x,y)) 
pl 
[[1]] 
function (x) 
pow(x, y) 
<environment: 0x09ccd5f8> 

[[2]] 
function (x) 
pow(x, y) 
<environment: 0x09ccd6bc> 

[[3]] 
function (x) 
pow(x, y) 
<environment: 0x09ccd780> 

Quando si tenta di valutare queste funzioni si ottengono risultati identici:

pl[[1]](2) 
[1] 8 
pl[[2]](2) 
[1] 8 
pl[[3]](2) 
[1] 8 

Che cosa sta succedendo qui, e come posso ottenere il risultato che desidero (le funzioni corrette nella lista)?

+0

Non sono sicuro, che cosa il vostro obiettivo è. Forse 'pl <- function (x, y) lapply (y, function (y) pow (x, y)); pl (2,1: 3) '? – Roland

+0

Queste note di Ross Ihaka (RCore) potrebbero essere utili (in particolare la parte su Lazy Evaluation) www.stat.auckland.ac.nz/~ihaka/downloads/Waikato-WRUG.pdf –

+0

Si noti che questo non è più vero a partire da R 3.2.0, vedi la mia risposta qui sotto. – jhin

risposta

20

R passa promises, non i valori stessi. La promessa è forzata quando viene valutata per la prima volta, non quando viene passata, e da quel momento l'indice è cambiato se si usa il codice nella domanda. Il codice può essere scritto come segue per force la promessa al momento della funzione anonima esterno è chiamato e per far capire al lettore:

pl <- lapply(1:3, function(y) { force(y); function(x) pow(x,y) }) 
+0

Grazie, è bello sapere come funziona questa trappola. Dovrò tenerlo a mente in futuro. – James

4

Questo non è più vero, come di R 3.2.0!

La riga corrispondente nella change log legge:

funzioni di ordine superiore come le funzioni applicare e ridurre() ora argomenti forza alle funzioni applicate per eliminare interazioni indesiderate tra valutazione pigra e cattura variabile in chiusure.

E infatti:

pow <- function(x,y) x^y 
pl <- lapply(1:3,function(y) function(x) pow(x,y)) 
pl[[1]](2) 
# [1] 2 
pl[[2]](2) 
# [1] 4 
pl[[3]](2) 
# [1] 8 
+0

Questa è una buona notizia. – James