promessa già in fase di valutazione: riferimento di argomento predefinito ricorsivo o problemi precedenti?


143

Ecco il mio codice R. Le funzioni sono definite come:

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}

g <- function(x, T, f=f) {
  exp(-f(x) / T)
}

test <- function(g=g, T=1) { 
  g(1, T)
}

L'errore di esecuzione è:

> test ()
Errore nel test ():
promessa già in fase di valutazione: riferimento argomento predefinito ricorsivo o problemi precedenti?

Se sostituisco la definizione di fin quella di g, l'errore scompare.

Mi chiedevo quale fosse l'errore? Come correggerlo se non si sostituisce la definizione di fin quella di g? Grazie!


Aggiornare:

Grazie! Due domande:

(1) se la funzione testaccetta ulteriormente un argomento f, aggiungerai qualcosa del genere test <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }? Nei casi con più ricorsioni, è una buona pratica sicura aggiungere altro . ?

(2) se fun argomento non funzionale, ad esempio , g <- function(x, T, f=f){ exp(-f*x/T) }e l' test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }uso dello stesso nome per argomenti non funzionali sia formali che reali è una pratica buona e sicura o può causare qualche potenziale problema?

Risposte:


159

Argomenti formali del modulo x=xcausano questo. Eliminando i due casi in cui si verificano, otteniamo:

f <- function(x, T) {
   10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}

g <- function(x, T, f. = f) {  ## 1. note f.
   exp(-f.(x)/T) 
}

test<- function(g. = g, T = 1) {  ## 2. note g.
   g.(1,T) 
}

test()
## [1] 8.560335e-37

2
Grazie! Due domande (1) se il test di funzione accetta ulteriormente un argomento per f , aggiungerai qualcosa come test <- function (g. = G, T = 1, f .. = f) {g. (1, T, f. = f ..)} ? Nei casi con più ricorsioni, è una buona pratica sicura aggiungere altro . ? (2) se f è un argomento non funzionale, ad esempio g <- funzione (x, T, f = f) {exp (-f x / T)} * e test <- funzione (g. = G, T = 1, f = f) {g. (1, T, f = f.)} , Usando lo stesso nome per argomenti non funzionali sia formali che reali una pratica buona e sicura o può causare qualche potenziale problema?
Tim

16
Qualche altra soluzione? Sto passando alcuni argomenti abbastanza in profondità nella catena di funzioni (circa 5 livelli), e questa soluzione può diventare .....cumbersome. :)
Roman Luštrik,

2
@ RomanLuštrik Se si stanno tramandando gli argomenti e si può tranquillamente ignorarne alcuni, quindi utilizzare ellissi ...o un elenco per passare gli argomenti nella catena delle funzioni. È molto più flessibile (nel bene e nel male) rispetto alla pre-definizione di tutto. Potresti semplicemente dover aggiungere alcuni controlli per assicurarti che i tuoi argomenti originali tra i puntini di sospensione (o elenco) siano ragionevoli.
Russellpierce,

2
Un'altra opzione qui è quella di tentare esplicitamente di trovare gli argomenti in un frame principale, aggirando la forzatura accidentale della promessa attiva - ad es get("f", envir = parent.frame()).
Kevin Ushey,

1
L'unico requisito è che non si usi lo stesso nome sul lato sinistro e destro. A parte questo, è solo stile.
G. Grothendieck,

13

Se si specifica il contesto di valutazione degli argomenti, si evita il problema con lo stesso nome:

f <- function(x) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}
g <- function(x, t=1, f=parent.frame()$f) {
  exp(-f(x) / t)
}
test <- function(g=parent.frame()$g, t=1) { 
  g(1,t)
}
test()
[1] 8.560335e-37

2
Questo è un modo migliore, penso che specificare l'ambiente sia più chiaro
cloud calcola l'

1

Mi piace la risposta di G. Grothendieck , ma mi chiedevo che nel tuo caso sia più semplice non includere i nomi delle funzioni nei parametri delle funzioni, in questo modo:

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}
g <- function(x, T) {
  exp(-f(x)/T) 
}
test<- function(T = 1) {
  g(1,T)
}
test()
## [1] 8.560335e-37

1

Come già accennato, il problema deriva dall'avere un argomento di funzione definito come se stesso. Tuttavia, voglio aggiungere una spiegazione del perché questo è un problema perché la comprensione mi ha portato a un modo più semplice (per me) di evitare il problema: basta specificare l'argomento nella chiamata anziché la definizione.

Questo non funziona:

x = 4
my.function <- function(x = x){} 
my.function() # recursive error!

ma questo funziona:

x = 4
my.function <- function(x){} 
my.function(x = x) # works fine!

Gli argomenti delle funzioni esistono nel loro ambiente locale.

R cerca prima le variabili nell'ambiente locale, poi nell'ambiente globale. Questo è proprio come all'interno di una funzione una variabile può avere lo stesso nome di una variabile nell'ambiente globale e R utilizzerà la definizione locale.

Avere le definizioni degli argomenti delle funzioni nel proprio ambiente locale è il motivo per cui si possono avere valori di argomenti predefiniti basati su altri valori di argomento, come

my.function <- function(x, two.x = 2 * x){}

Quindi questo è il motivo per cui non è possibile DEFINIRE una funzione in quanto my.function <- function(x = x){}è possibile CHIAMARE la funzione utilizzando my.function(x = x). Quando si definisce la funzione, R viene confuso perché trova l'argomento x =come valore locale di x, ma quando si chiama la funzione che R trova x = 4nell'ambiente locale da cui si sta chiamando.

Quindi, oltre a correggere l'errore modificando il nome dell'argomento o specificando esplicitamente l'ambiente come indicato in altre risposte, puoi anche specificare che x=xquando chiami la funzione anziché quando la definisci. Per me, specificare che x=xnella chiamata era la soluzione migliore, dal momento che non comporta una sintassi aggiuntiva o accumulare sempre più nomi di variabili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.