Une fonction - formellement appelée fermeture dans la documentation R - comprend non seulement ses arguments et son corps, mais aussi son environnement. Ce dernier est constitué de la collection d'objets présents au moment de la création de la fonction. Une compréhension de la façon dont les environnements fonctionnent dans R est essentielle pour écrire des fonctions R efficaces.
1 L'environnement de premier niveau
Considérez cet exemple:
Ici, la fonction f () est créée au niveau supérieur, c'est-à-dire à l'invite de commande inter¬prètre, et a donc l'environnement de niveau supérieur, qui dans la sortie R est appelé R_GlobalEnv mais que vous référez de manière confuse Code R comme .GlobalEnv. Si vous exécutez un programme R en tant que fichier de commandes, cela est également considéré comme le niveau supérieur.
La fonction ls () répertorie les objets d'un environnement. Si vous l'appelez au niveau supérieur, vous obtenez l'environnement de niveau supérieur. Essayons avec notre code d'exemple:
Comme vous pouvez le voir, l'environnement de niveau supérieur inclut ici la variable w, qui est effectivement utilisée dans f (). Notez que f () est ici aussi, car les fonctions sont en effet des objets et nous l'avons créé au niveau supérieur. Aux niveaux autres que le sommet, ls () fonctionne un peu différemment, comme vous le verrez dans la section 7.6.3.
Vous obtenez un peu plus d'informations de ls.str ():
Ensuite, nous verrons comment w et d'autres variables entrent en jeu dans f ().
2 La hiérarchie de portée
Nous allons d'abord obtenir une vue d'ensemble intuitive de la façon dont fonctionne la portée dans R, puis la relier aux environnements.
Si nous travaillons avec le langage C, nous dirons que la variable w dans la section précédente est globale à f (), tandis que d est local à f (). Les choses sont similaires dans R, mais R est plus hiérarchique. En C, nous n'aurions pas de fonctions définies dans les fonctions, comme nous avons avec h () à l'intérieur de f () dans notre exemple. Cependant, puisque les fonctions sont des objets, il est possible - et parfois souhaitable du point de vue de l'objectif d'encapsulation de la programmation orientée objet - de définir une fonction dans une fonction; nous créons simplement un objet, que nous pouvons faire n'importe où.
Ici, nous avons h () étant local à f (), tout comme d. Dans une telle situation, il est logique que la portée soit hiérarchique. Ainsi, R est établi de sorte que d, qui est local à f (), est à son tour global à h (). Il en est de même pour y, car les arguments sont considérés comme des sections locales dans R.
De même, la nature hiérarchique de la portée implique que puisque w est global à f (), elle est aussi globale à h (). En effet, nous utilisons w dans h ().
En termes d'environnements, alors, l'environnement de h () consiste en ce que les objets sont définis à l'instant h () existe; c'est-à-dire au moment où cette affectation est exécutée:
(Si f () est appelé plusieurs fois, h () apparaît plusieurs fois, sortant de son existence chaque fois que f () retourne.)
Quel sera donc l'environnement de h ()? Eh bien, au moment de la création de h (), les objets d et y sont créés dans f (), plus l'environnement (w) de f ().
En d'autres termes, si une fonction est définie dans un autre, alors l'environnement de cette fonction interne est constitué de l'environnement de l'environnement externe, plus tout ce que les locaux ont été créés jusqu'à présent dans l'environnement externe. Avec une imbrication multiple des fonctions, vous avez une séquence imbriquée d'environnements de plus en plus grands, la racine étant constituée des objets de niveau supérieur.
Essayons le code:
Qu'est-il arrivé? L'appel f (2) a abouti à la définition de la variable locale d à 8, suivie de l'appel h (). Ce dernier a évalué d * (w + y) - c'est-à-dire 8 * (i2 + 2) - nous donnant 112.
Notez attentivement le rôle de w. L'interprète R a trouvé qu'il n'y avait pas de variable locale de ce nom, donc il est passé au niveau supérieur suivant - dans ce cas, le niveau supérieur - où il a trouvé une variable w avec la valeur 12.
Gardez à l'esprit que h () est local à f () et invisible au niveau supérieur.
Il est possible (mais pas souhaitable) d'autoriser délibérément les conflits de noms dans cette hiérarchie. Dans notre exemple, par exemple, nous pourrions avoir une variable locale d dans h (), en conflit avec celle de f (). Dans une telle situation, l'environnement le plus interne est utilisé en premier. Dans ce cas, une référence à d dans h () ferait référence aux d, et non à f () de h ().
Les environnements créés par héritage de cette manière sont généralement désignés par leurs emplacements de mémoire. Voici ce qui s'est passé après avoir ajouté une instruction print à f () (en utilisant edit (), non montré ici) et en exécutant le code: