2009-07-23 16 views
30

Scrivo spesso funzioni che necessitano di vedere altri oggetti nel mio ambiente. Ad esempio:Scrittura di funzioni in R, tenendo presente l'ambito dell'ottimizzazione

> a <- 3 
> b <- 3 
> x <- 1:5 
> fn1 <- function(x,a,b) a+b+x 
> fn2 <- function(x) a+b+x 
> fn1(x,a,b) 
[1] 7 8 9 10 11 
> fn2(x) 
[1] 7 8 9 10 11 

Come previsto, entrambe queste funzioni sono identiche perché fn2 può "vedere" A e B quando viene eseguito. Ma ogni volta che inizio a trarne vantaggio, entro circa 30 minuti finisco per chiamare la funzione senza una delle variabili necessarie (ad esempio a o b). Se non ne approfitto, allora mi sento come se stessi passando oggetti inutilmente.

È meglio essere espliciti su cosa richiede una funzione? O questo dovrebbe essere curato tramite commenti in linea o altra documentazione della funzione? C'è un modo migliore?

risposta

36

Se so che sto andando avere bisogno di una funzione parametrizzata alcuni valori e chiamato più volte, evito globali utilizzando una chiusura:

make.fn2 <- function(a, b) { 
    fn2 <- function(x) { 
     return(x + a + b) 
    } 
    return(fn2) 
} 

a <- 2; b <- 3 
fn2.1 <- make.fn2(a, b) 
fn2.1(3) # 8 
fn2.1(4) # 9 

a <- 4 
fn2.2 <- make.fn2(a, b) 
fn2.2(3) # 10 
fn2.1(3) # 8 

questo modo si evita accuratamente riferimento a variabili globali, utilizzando invece la racchiude ambiente della funzione per a e b. La modifica dei globali a e b non porta a effetti collaterali indesiderati quando vengono chiamate istanze fn2.

3

Il problema si verifica quando si utilizza solo una variabile globale in una funzione o quando si tenta di assegnare la variabile? Se è il secondo, sospetto che sia perché non stai usando <<- come un incarico all'interno della funzione. E mentre si utilizza <<- sembra essere il lato oscuro 1 potrebbe funzionare molto bene per i vostri scopi. Se è il primo, la funzione probabilmente sta mascherando la variabile globale.

È possibile assegnare nomi alle variabili globali in modo che sia difficile mascherarle localmente. ad esempio: global.pimultiples <- 1:4*pi

8

C'è un motivo per cui alcune lingue non consentono variabili globali: possono facilmente portare a codice non funzionante.

Le regole di scoping in R consentono di scrivere codice in modo lazy - lasciare che le funzioni utilizzino variabili in altri ambienti può farti risparmiare un po 'di digitazione, ed è ottimo per giocare in casi semplici.

Se si sta facendo qualcosa di remoto, tuttavia, si consiglia di passare una funzione a tutte le variabili di cui ha bisogno (o, per lo meno, avere qualche controllo approfondito di integrità per avere un ripiego nel caso in cui le variabili indichino Esistono).

Nell'esempio sopra:

La pratica migliore è quella di utilizzare fn1.

In alternativa, provare qualcosa di simile

fn3 <- function(x) 
    { 
     if(!exists("a", envir=.GlobalEnv)) 
     { 
     warning("Variable 'a' does not exist in the global environment") 
     a <- 1 
     } 

     if(!exists("b", envir=.GlobalEnv)) 
     { 
     warning("Variable 'b' does not exist in the global environment") 
     b <- 2 
     } 

     x + a + b 
    } 
0

L'utilizzo di variabili globali è scoraggiato generale nella maggior parte delle lingue, e R non fa eccezione. Molto spesso una funzione breve utilizza nomi di variabili brevi e generici, che potrebbero essere popolati nell'ambiente globale. È più sicuro a) includere tutte le variabili nella definizione della funzione b) non per assegnare valori predefiniti. Ad esempio, scrivi f = funzione (a, b), piuttosto f = funzione (a = 0, b = NA).