2014-04-02 5 views
6

Qui creo un'espressione non valutata:Qual è il meccanismo che rende `+` funzionante quando definito da + in un ambiente vuoto?

e2 <- expression(x+10) 

Se io fornisco un ambiente in cui x è definito come

env <- as.environment(list(x=20)) 
eval(e2,env) 

R segnalerà un errore:

Error in eval(expr, envir, enclos) : could not find function "+" 

è comprensibile dal env è un ambiente creato da zero, cioè non ha un ambiente genitore dove + è definito.

Tuttavia, se fornisco + nella lista per essere convertito in un ambiente come questo

env <- as.environment(list(x=20,`+`=function(a,b) {a+b})) 
eval(e2,env) 

La valutazione funziona correttamente e rese 30.

Tuttavia, quando definisco + nella lista, è una funzione binaria il cui corpo usa anche + che è definito in {base}. So che i ritorni delle funzioni sono ponderati in R, ma perché potrebbe funzionare? Se il valore a+b nel corpo della funzione viene valutato pigramente, quando si chiama eval per e2 all'interno di env, anche se + è definito in questo ambiente che non ha un ambiente principale, dovrebbe comunque chiamare + in sé, che dovrebbe finire in un ciclo infinito. Perché non succede così? Qual è il meccanismo qui?

+0

È possibile trovare http://adv-r.had.co.nz/Environments.html utile. – hadley

+0

È bello vederti qui, @hadley! Ho letto il tuo fantastico nuovo libro online un mese fa. Forse mi manca un punto e ce ne sono sicuramente di più da digerire. Grazie comunque! –

+1

La distinzione principale è "l'ambiente in cui viene creata la funzione" rispetto a "l'ambiente in cui si trova la funzione" – hadley

risposta

4

Quando si definisce l'ambiente qui:

env <- as.environment(list(x=20,`+`=function(a,b) {a+b})) 

quindi la definizione di funzione è in realtà definita nella .GlobalEnv (vale a dire, in cui viene eseguita la definizione Lo si può verificare:.

$ environment(env$`+`) 
<environment: R_GlobalEnv> 

Questo l'osservazione vale la pena di essere ponderata un po ': una funzione può essere un membro dell'ambiente x, ma appartiene a (dove "appartiene a" significa che la sua ricerca dell'oggetto utilizza piuttosto che n x).

E .GlobalEnv sa di +, poiché è definito da qualche parte nei suoi genitori (accessibile tramite search()).

Per inciso, se si fosse usato list2env invece di as.environment, il codice iniziale avrebbe funzionato:

$ env = list2env(list(x = 20)) 
$ eval(e2, env) 
30 

La ragione è che, a differenza as.environment, list2env di default usa contesto attuale come genitore del nuovo ambiente (questo può essere controllato tramite l'argomento parent). as.environment utilizza invece l'ambiente vuoto (quando si crea un ambiente da un elenco).

+0

sorprendente risposta rapida! Grazie! È ancora incredibile che una funzione possa essere membro di un ambiente ma esegua la ricerca di oggetti in un altro ambiente. C'è una ragione che lo renda semplice? –

+0

@KunRen La ragione è che l'ambiente di una funzione è il luogo in cui è stata eseguita la sua definizione - nel tuo caso, questo è l'ambiente globale. Se si volesse creare una funzione all'interno di 'env', si potrebbe usare' within' o 'local'. Non conosco il motivo di questo comportamento, ma ha senso, ed è necessario per l'implementazione dei pacchetti, vedere http://obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/. –

+0

Articolo molto utile! –

Problemi correlati