promesse déjà en cours d'évaluation: référence d'argument récursif par défaut ou problèmes antérieurs?


143

Voici mon code R. Les fonctions sont définies comme:

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'erreur de fonctionnement est:

> test ()
Erreur dans test ():
promesse déjà en cours d'évaluation: référence d'argument récursif par défaut ou problèmes antérieurs?

Si je remplace la définition de fpar celle de g, l'erreur disparaît.

Je me demandais quelle était l'erreur? Comment le corriger si on ne substitue pas la définition de fà celle de g? Merci!


Mettre à jour:

Merci! Deux questions:

(1) si la fonction testprend en outre un argument pour f, allez-vous ajouter quelque chose comme test <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }? Dans les cas où il y a plus de récursions, est-ce une bonne et sûre pratique d'ajouter plus . ?

(2) si fun argument non fonctionnel, par exemple g <- function(x, T, f=f){ exp(-f*x/T) }et test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }, est-ce que l'utilisation du même nom pour les arguments non fonctionnels formels et réels est-elle une bonne et sûre pratique ou cela peut causer des problèmes potentiels?

Réponses:


159

Les arguments formels de la forme x=xprovoquent cela. En éliminant les deux cas où ils se produisent, nous obtenons:

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
Merci! Deux questions (1) si le test de fonction prend en outre un argument pour f , ajouterez-vous quelque chose comme test <- fonction (g. = G, T = 1, f .. = f) {g. (1, T, f. = f ..)} ? Dans les cas où il y a plus de récursions, est-ce une bonne et sûre pratique d'ajouter plus . ? (2) si f est un argument non fonctionnel, par exemple g <- function (x, T, f = f) {exp (-f x / T)} * et test <- function (g. = G, T = 1, f = f) {g. (1, T, f = f.)} , Est-ce que l'utilisation du même nom pour les arguments non fonctionnels formels et réels sera une bonne et sûre pratique ou cela peut causer des problèmes potentiels?
Tim

16
D'autres solutions? Je passe quelques arguments assez profondément dans la chaîne des fonctions (environ 5 niveaux), et cette solution peut devenir .....cumbersome. :)
Roman Luštrik

2
@ RomanLuštrik Si vous transmettez les arguments et que vous pouvez en ignorer certains en toute sécurité, envisagez d'utiliser des points de suspension ...ou une liste pour transmettre les arguments dans la chaîne de fonctions. C'est beaucoup plus flexible (pour le meilleur et pour le pire) que de tout prédéfinir. Vous pourriez finir par avoir besoin d'ajouter quelques vérifications pour vous assurer que vos arguments d'origine dans les ellipses (ou la liste) sont raisonnables.
russellpierce

2
Une autre option ici est d'essayer explicitement de trouver les arguments dans une trame parent, en contournant le forçage accidentel de la promesse active - par exemple get("f", envir = parent.frame()).
Kevin Ushey

1
La seule exigence est que vous n'utilisiez pas le même nom à gauche et à droite. A part ça, c'est juste du style.
G. Grothendieck

13

Si vous spécifiez le contexte d'évaluation des arguments, vous évitez le problème du même nom:

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
C'est un meilleur moyen, je pense que spécifier que l'environnement est plus clair
cloudscomputes

1

J'aime la réponse de G. Grothendieck , mais je me demandais que c'est plus simple dans votre cas de ne pas inclure les noms de fonctions dans les paramètres des fonctions, comme ceci:

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

Comme déjà mentionné, le problème vient d'avoir un argument de fonction défini comme lui-même. Cependant, je veux ajouter une explication de la raison pour laquelle c'est un problème parce que la compréhension qui m'a conduit à un moyen plus simple (pour moi) d'éviter le problème: il suffit de spécifier l'argument dans l'appel au lieu de la définition.

Cela ne fonctionne pas:

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

mais cela fonctionne:

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

Les arguments de fonction existent dans leur propre environnement local.

R recherche d'abord les variables dans l'environnement local, puis dans l'environnement global. C'est comme dans une fonction qu'une variable peut avoir le même nom qu'une variable dans l'environnement global, et R utilisera la définition locale.

Le fait que les définitions d'arguments de fonction forment leur propre environnement local est la raison pour laquelle vous pouvez avoir des valeurs d'argument par défaut basées sur d'autres valeurs d'argument, comme

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

C'est pourquoi vous ne pouvez pas DEFINIR une fonction comme my.function <- function(x = x){}mais vous pouvez APPELER la fonction en utilisant my.function(x = x). Lorsque vous définissez la fonction, R devient confus car il trouve l'argument x =comme valeur locale de x, mais lorsque vous appelez la fonction, R trouve x = 4dans l'environnement local à partir duquel vous appelez .

Ainsi, en plus de corriger l'erreur en modifiant le nom de l'argument ou en spécifiant explicitement l'environnement comme mentionné dans d'autres réponses, vous pouvez également simplement le spécifier x=xlorsque vous appelez la fonction plutôt que lorsque vous la définissez. Pour moi, spécifier cela x=xdans l'appel était la meilleure solution, car cela n'implique pas de syntaxe supplémentaire ni d'accumulation de plus en plus de noms de variables.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.