Versprechen bereits in der Bewertung: rekursive Standardargumentreferenz oder frühere Probleme?


143

Hier ist mein R-Code. Die Funktionen sind definiert als:

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)
}

Der laufende Fehler ist:

> test ()
Fehler in test ():
Versprechen wird bereits evaluiert: rekursive Standardargumentreferenz oder frühere Probleme?

Wenn ich die Definition von fin die von gersetze, verschwindet der Fehler.

Ich habe mich gefragt, was der Fehler war. Wie kann man das korrigieren, wenn man die Definition von nicht fdurch die von ersetzt g? Vielen Dank!


Aktualisieren:

Vielen Dank! Zwei Fragen:

(1) Wenn die Funktion testweiter ein Argument für nimmt f, werden Sie so etwas hinzufügen test <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }? In Fällen mit mehr Rekursionen ist es eine gute und sichere Praxis, mehr hinzuzufügen . ?

(2) Wenn fes sich beispielsweise um ein Nichtfunktionsargument handelt g <- function(x, T, f=f){ exp(-f*x/T) }und test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }die Verwendung des gleichen Namens sowohl für formale als auch für tatsächliche Nichtfunktionsargumente eine gute und sichere Praxis ist, kann dies zu potenziellen Problemen führen?

Antworten:


159

Formale Argumente der Form x=xverursachen dies. Wenn wir die beiden Fälle eliminieren, in denen sie auftreten, erhalten wir:

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
Vielen Dank! Zwei Fragen (1) , wenn die Funktion Test nimmt weiter ein Argument für f , werden Sie etwas hinzufügen , wie Test <- (. G = g, T = 1, f .. = f) Funktion {g (1, T, f.. = f ..)} ? In Fällen mit mehr Rekursionen ist es eine gute und sichere Praxis, mehr hinzuzufügen . ? (2) Wenn f ein Nichtfunktionsargument ist, zum Beispiel g <- Funktion (x, T, f = f) {exp (-f x / T)} * und test <- Funktion (g. = G, T. = 1, f = f) {g. (1, T, f = f.)} , Wird die Verwendung des gleichen Namens für formale und tatsächliche nicht funktionale Argumente eine gute und sichere Praxis sein oder kann dies zu potenziellen Problemen führen?
Tim

16
Irgendwelche anderen Lösungen? Ich übergebe einige Argumente ziemlich tief in der Funktionskette (ungefähr 5 Ebenen), und diese Lösung kann werden .....cumbersome. :)
Roman Luštrik

2
@ RomanLuštrik Wenn Sie die Argumente weitergeben und einige davon ignorieren können, sollten Sie Ellipsen ...oder eine Liste verwenden, um die Argumente entlang der Funktionskette weiterzugeben. Es ist viel flexibler (für gut und schlecht) als alles vorab zu definieren. Möglicherweise müssen Sie nur einige Überprüfungen hinzufügen, um sicherzustellen, dass Ihre ursprünglichen Argumente in den Ellipsen (oder in der Liste) sinnvoll sind.
Russellpierce

2
Eine andere Möglichkeit besteht darin, explizit zu versuchen, die Argumente in einem übergeordneten Frame zu finden, wobei das versehentliche Erzwingen des aktiven Versprechens umgangen wird - z get("f", envir = parent.frame()).
Kevin Ushey

1
Die einzige Voraussetzung ist, dass Sie links und rechts nicht denselben Namen verwenden. Davon abgesehen ist es nur Stil.
G. Grothendieck

13

Wenn Sie den Kontext für die Argumentbewertung angeben, vermeiden Sie das gleichnamige Problem:

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
Dies ist ein besserer Weg, ich denke, angeben, die Umgebung ist klarer
Cloudscomputes

1

Ich mag die Antwort von G. Grothendieck , aber ich habe mich gefragt, dass es in Ihrem Fall einfacher ist, Funktionsnamen nicht in die Parameter von Funktionen aufzunehmen, wie folgt:

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

Wie bereits erwähnt, besteht das Problem darin, dass ein Funktionsargument als sich selbst definiert ist. Ich möchte jedoch eine Erklärung hinzufügen, warum dies ein Problem ist, da das Verständnis mich zu einer (für mich) einfacheren Möglichkeit geführt hat, das Problem zu vermeiden: Geben Sie einfach das Argument im Aufruf anstelle der Definition an.

Das funktioniert nicht:

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

aber das funktioniert:

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

Funktionsargumente existieren in ihrer eigenen lokalen Umgebung.

R sucht zuerst in der lokalen Umgebung nach Variablen, dann in der globalen Umgebung. Dies ist genau so, wie innerhalb einer Funktion eine Variable denselben Namen wie eine Variable in der globalen Umgebung haben kann und R die lokale Definition verwendet.

Wenn Funktionsargumentdefinitionen eine eigene lokale Umgebung bilden, können Sie Standardargumentwerte verwenden, die auf anderen Argumentwerten basieren, z

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

Aus diesem Grund können Sie eine Funktion nicht als definieren, my.function <- function(x = x){}sondern die Funktion mit aufrufen my.function(x = x). Wenn Sie die Funktion definieren, wird R verwirrt, weil das Argument x =als lokaler Wert von gefunden xwird. Wenn Sie jedoch die Funktion aufrufen, die R x = 4in der lokalen Umgebung findet, aus der Sie aufrufen.

Zusätzlich zur Behebung des Fehlers durch Ändern des Argumentnamens oder expliziten Angeben der Umgebung, wie in anderen Antworten erwähnt, können Sie dies auch nur angeben, x=xwenn Sie die Funktion aufrufen, anstatt sie zu definieren. Für mich x=xwar es die beste Lösung, dies im Aufruf anzugeben , da es keine zusätzliche Syntax oder das Sammeln von immer mehr Variablennamen erfordert.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.