2016-05-06 30 views
5

Dopo l'esecuzione:In R, esattamente ciò che causa la valutazione di un oggetto di tipo nome (o simbolo)?

x <- as.name("aa") 
aa <- 2 

in R, perché non lo fa

(x) 

ritorno 2? E perché non

x <- as.name("aa") 
aa <- 3 
get(get(x)) 

ritorno 3?

So che get() si aspetta una stringa, ma non capisco perché non valuta x, trova la stringa all'interno, e poi la ottiene. A volte mi sembra che funzioni svolgano una tale valutazione dei loro argomenti, e talvolta non lo fanno. Ad esempio, nel secondo esempio, se si sostituisce get (get (x)) con eval (x), eval() valuta la x per trovare il nome, quindi valuta il nome per trovare 3.

+2

Sono sconcertato dalla tua modifica. Sembra che tu stia chiedendo perché gli sviluppatori di R non hanno fatto "get' do cosa fa" eval', ma poi la risposta dovrebbe essere perché fanno due cose diverse: una valuta un'espressione (che può essere un simbolo) e l'altro recupera oggetti dove si specifica il nome (simbolo) dell'oggetto tramite un carattere. Perché non dovresti_ dividere funzionalità diverse in due diverse funzioni? – joran

risposta

5

Penso che la risposta di @joran sia giusta ma forse posso provare a spiegare un modo diverso.

La "funzione" ( in R è essenzialmente la funzione di identità. Ripercorre ciò che hai passato. È quasi come se non fosse lì. Non c'è differenza tra ciò che verrà restituito da queste dichiarazioni

x  #1 
(x) #2 
((x)) #3 

La parentesi appena passthrough il valore all'interno. Puoi aggiungere tutte le parentesi che vuoi e non cambierà ciò che viene restituito. Il valutatore esamina ((x)), vede la parentesi esterna e sa di restituire semplicemente il valore della cosa all'interno della parentesi. Quindi ora sta analizzando solo (x), e di nuovo, vede la parentesi esterna e restituirà semplicemente il valore all'interno della parentesi, che è x. La parentesi passa solo attraverso il valore dall'interno; non lo valutano

Il valore nudo x è un nome (o simbolo). Un nome non è legato unicamente a un valore. La mappatura tra nomi e valori varia in base all'ambiente. Ecco perché i nomi devono essere valutati in un particolare contesto per ottenere un valore.Considerare questi esempi

aa <- 5 
dd <- data.frame(aa=20) 
x <- as.name("aa") 
foo <- function(x) {aa<-10; eval(x)} 

eval(x) 
# [1] 5 
foo(x) 
# [1] 10 
eval(x, dd) 
# [1] 20 

Questo comportamento è in realtà altamente auspicabile. E 'ciò che rende le funzioni che richiedono il lavoro di valutazione non standard, come

subset(mtcars, hp<100) 

Quando si utilizza la console di R, si comporta come una REPL - si legge l'input, lo valuta, lo stampa, e quindi attende l'input successivo. Si noti che fa solo un livello di valutazione e la valutazione avviene nell'ambiente "corrente". Non valuta in modo ricorsivo il valore restituito da un'espressione. Quindi, quando si fa

x <- as.name("aa") 
x # identical to (x) 
# aa 

quando il REPL arriva alla fase di valutazione, valuta il nome x che punta al nome aa. Questo è tutto. Un livello di valutazione. Il nome aa non viene successivamente valutato.

C'è una nota nella pagina ?eval aiuto che dice questo:

eval valuta il suo primo argomento nell'ambito corrente prima di passarlo al valutatore

Non c'è un "doppio" la valutazione sta accadendo lì. Sta semplicemente valutando i suoi parametri proprio come qualsiasi altra funzione in R. Per esempi

aa <- 5 
bar <- function(x) print(x) 
bar(aa+2) 
# [1] 7 

Esso stampa "7", non "AA + 2" perché la funzione ha valutato che è il parametro prima della stampa. Si spiega anche le differenze tra questi due

dd <- data.frame(bb=20) 
xx <- as.name("bb") 
eval(bb, dd) 
# Error in eval(bb, dd) : object 'bb' not found 
eval(xx, dd) 
# [1] 20 

Nel primo eval() chiamata, R è in grado di valutare bb nel contesto attuale in modo da ottenere l'errore. Ma nota che

evalq(bb, dd) 

funziona perché evalq non cerca di valutare il primo parametro espressione.

+0

Caro @MrFlick Questo è molto utile. Ma ancora non capisco perché dato: x <- as.name ("aa"); aa <- 2; if (x) restituisce la stessa cosa di x alla riga di comando (che fa: il simbolo aa), perché no ((x)) restituisce 2? (x) restituisce aa alla riga di comando e aa restituisce 2. – andrewH

+0

Perché qui è presente un solo "ritorno". La linea viene valutata esattamente una volta. Non c'è una doppia valutazione. Le parentesi non forzano la valutazione. – MrFlick

+0

OK, quindi forse ce l'ho. Le parentesi davvero, davvero non fanno altro che il gruppo. Nello specifico, non fanno la stessa cosa che digitare x nella console R. È la linea di comando della console R, che, come si dice, si comporta come un ciclo Read-eval-print, non la funzione '('. Quindi ((x)) arriva alla riga di comando come x, non come aa. Non diventa aa finché non arriva la riga di comando, ed è la linea di comando della console che risolve la x in aa. Mettere in più livelli di parentesi non fa alcuna differenza perché anche le parentesi più interne non fanno nulla a x. È giusto? – andrewH

10

Perché il valore di x non è 2, è il simbolo (o nome) aa. Tuttavia, se si eval esso:

> eval(x) 
[1] 2 

Allo stesso modo, get(x) non funziona affatto (cioè produce un errore) perché secondo la documentazione per get, è primo argomento deve essere an object name (given as a character string), dove la parentesi è destinato a distinguerlo da un simbolo/nome.

get funziona solo con un argomento di carattere:

> get("aa") 
[1] 2 

E un symbol (che trovo meno confusione di name) non è la stessa cosa:

> identical("aa",as.name("aa")) 
[1] FALSE 

(as.name e as.symbol fare il stessa cosa.)

Per un'eccellente spiegazione della "valutazione delle espressioni" vs Distinzione "valutazione di argomenti di funzione" Di seguito ho citato in un commento, vedere @ Risposta di MrFlick.

+0

Penso che quello che rimango confuso sia il motivo per cui R si comporta diversamente se digito un simbolo piuttosto che se una funzione restituisce lo stesso simbolo. eval (x) non restituisce un simbolo: valuta l'espressione x, trova un simbolo e quindi valuta il simbolo per trovare il valore. La valutazione avviene due volte. Se scrivo (aa), R restituisce 2. se digito x, R restituisce aa, di tipo symbol. Ma se digito (x), R restituisce ancora il simbolo. Non capisco perché, dopo che le parentesi interne hanno valutato un simbolo, le parentesi esterne non restituiscono quello che fanno se digito lo stesso simbolo tra parentesi. – andrewH

+0

Il mio esempio get() era mal costruito. Permettimi di riformulare. Se digito (get ("x")), proprio come sopra, restituisce nuovamente un simbolo. All'altro estremo, get ("get (" x ")") restituisce un errore. Non valuta get ("x") su un simbolo, inserisce virgolette e valuta il simbolo quotato. Questo ha più senso per me, ma solo perché non mi aspetto che le virgolette si comportino come una funzione regolare, valutando il suo argomento e quindi restituendo il risultato come una stringa. Ma in (get ("x")), mi aspetto che l'argomento della parentesi esterna sia valutato, e non lo è. – andrewH

+0

@andrewH Penso che tu stia confondendo "valutando un'espressione R arbitraria in un ambiente specifico" con "valutare un argomento di funzione", dove quest'ultimo in realtà significa qualcosa di più vicino a "legare una promessa ad un valore". '()' si comporta semanticamente come la funzione 'identity', quindi qualsiasi" valutazione "dei suoi _arguments_ significa semplicemente che risolverà la promessa di un valore. Si consideri l'identità (x = get ("x")) '. Quello che viene valutato è il _argument_ 'x', e il risultato è che è legato al valore restituito da' get ("x") '. – joran