Définir et appeler une fonction
Une fonction en R est une valeur, comme un nombre ou une chaîne. Tu en construis une avec le mot-clé function et tu l'épingles à un nom avec <-, exactement comme tu stockerais n'importe quoi d'autre dans une variable :
Les éléments : function(x) déclare un paramètre nommé x, les accolades contiennent le corps, et appeler square(4) exécute le corps avec x valant 4. Pour un corps d'une seule ligne les accolades sont facultatives - square <- function(x) x^2 est la même fonction - mais les accolades se lisent mieux dès que le corps grandit.
Comme une fonction est simplement une valeur, tout ce que tu sais sur les variables s'applique : tu peux la réaffecter, la passer à une autre fonction, ou la stocker dans une liste. Ce seul fait alimente la moitié du R idiomatique, y compris toute la famille apply.
Valeurs de retour : la dernière expression gagne
Une fonction R renvoie ce que produit sa dernière expression évaluée. Il n'y a pas d'instruction return obligatoire :
return() existe bel et bien, et fonctionne comme tu l'attends - il arrête immédiatement la fonction et renvoie son argument. Le R idiomatique le réserve aux sorties anticipées : abandonner en haut quand une entrée rend inutile le reste du travail. Associe-le à des tests if-else :
Écrire return(a / b) sur la dernière ligne ne serait pas faux, juste du bruit. Réserve return() aux sorties qui arrivent tôt, et laisse la dernière expression parler pour le chemin normal.
Valeurs par défaut et arguments nommés
Un paramètre peut porter une valeur par défaut, déclarée avec = dans la liste des paramètres. Les appelants satisfaits de la valeur par défaut omettent simplement l'argument :
Le troisième appel montre l'autre moitié de l'histoire : les arguments nommés. Quand tu écris name = "Ada" au site d'appel, la position cesse d'importer - R apparie d'abord par nom, puis remplit les paramètres restants par position. Deux règles pratiques en découlent :
- Mets les paramètres obligatoires en premier et ceux avec valeur par défaut après, pour que les appels positionnels restent naturels.
- Au site d'appel, nomme tout argument qui n'est pas évident d'après sa position.
greet("Ada", punctuation = "?")est plus clair que d'obliger un lecteur à compter les virgules.
Faire suivre des arguments avec ...
Le paramètre spécial ... (qu'on prononce « les points ») signifie « un nombre quelconque d'arguments supplémentaires ». Une fonction qui déclare ... peut accepter des arguments qu'elle n'a jamais listés et les transmettre à une autre fonction :
shout() ne sait pas et se moque de combien de mots tu passes - il les donne tous à paste(). Remarque que punctuation vient après les points : tout paramètre déclaré après ... ne peut être défini que par son nom, ce qui est exactement ce que tu veux pour des options. Ce motif de transmission est partout dans R de base - sapply(x, round, digits = 2) marche parce que sapply transmet digits = 2 à round via son propre ....
Le prix des points, c'est que les fautes de frappe passent en silence : écris punctation au lieu de punctuation et l'argument est simplement avalé par ... au lieu de lever une erreur. Garde petites les fonctions qui utilisent les points.
Fonctions anonymes
Quand une fonction n'est nécessaire qu'une fois - typiquement comme argument d'une autre fonction - tu peux te passer complètement du nom :
Les deux lignes font la même chose. function(x) x^2 est l'écriture classique ; \(x) x^2 est le raccourci ajouté dans R 4.1, où \ remplace le mot function. Elles sont identiques en tout point sauf le nombre de frappes - le raccourci n'est pas un autre genre de fonction.
Utilise une fonction anonyme quand l'opération tient sur une ligne et est liée à un seul site d'appel. Dès que tu colles la même lambda à deux endroits, ou qu'elle dépasse une ligne, donne-lui un nom - une fonction nommée est testable et se documente elle-même.
Portée : ce qu'une fonction peut voir
R utilise la portée lexicale : quand une fonction a besoin d'une variable qu'elle ne trouve ni parmi ses paramètres ni parmi ses affectations locales, elle cherche dans l'environnement où la fonction a été définie - pas où elle a été appelée. En pratique, ça veut dire qu'une fonction peut lire des variables du script qui l'entoure :
Le revers : une affectation dans une fonction ne fuit jamais à l'extérieur. rate <- 0.5 dans change_inside crée une variable locale toute neuve qui meurt au retour de la fonction ; le rate extérieur affiche toujours 0.1. C'est une fonctionnalité - les fonctions ne peuvent pas piétiner accidentellement ton espace de travail - mais ça surprend les débutants qui s'attendent à ce que l'affectation interne persiste. Si une fonction doit transmettre un résultat au monde extérieur, renvoie-le et affecte au site d'appel. (Il existe un opérateur <<- qui atteint l'extérieur ; considère-le comme une odeur de code tant que tu n'en as pas réellement besoin.)
Un exemple traité
Voici le motif payant : tu remarques que tu répètes trois lignes d'analyse, tu les emballes dans une fonction, tu la réutilises. Disons que tu résumes sans cesse des vecteurs de mesures :
Tout ce qui est dans cette page s'y trouve : un paramètre digits avec valeur par défaut, un appel nommé qui l'écrase, et une dernière expression (round(out, digits)) qui fait le retour. La fonction se lit comme une phrase, marche sur n'importe quel vecteur numérique, et vit en un seul endroit quand tu décideras d'ajouter une médiane.
Ce que tu retiens
nom <- function(args) { corps }crée une fonction ; la dernière expression évaluée est sa valeur de retour.return()est pour les sorties anticipées, pas pour la dernière ligne normale.- Les valeurs par défaut se déclarent avec
=dans la liste des paramètres ; les arguments nommés rendent les appels indépendants de l'ordre et lisibles. ...accepte et transmet tout argument supplémentaire - puissant, mais ça masque les fautes de frappe.function(x)et\(x)sont la même chose ; utilise les fonctions anonymes pour les traitements ponctuels d'une seule ligne.- Les fonctions lisent les variables de là où elles ont été définies ; les affectations à l'intérieur y restent.
Prochaine étape : la famille apply - les fonctions qui prennent tes fonctions et les exécutent sur des vecteurs et des listes entiers.
Questions fréquentes
Comment créer une fonction en R ?
Affecte un objet function à un nom : square <- function(x) { x^2 }. Les paramètres vont entre parenthèses, le corps entre accolades, et tu l'appelles avec square(4). La dernière expression évaluée est ce que la fonction renvoie.
A-t-on besoin de return() en R ?
Non. Une fonction R renvoie automatiquement la valeur de la dernière expression qu'elle évalue. return() existe, et le R idiomatique le réserve aux sorties anticipées - abandonner en haut d'une fonction quand une entrée est invalide ou qu'un cas limite est traité.
Qu'est-ce qu'une fonction anonyme en R ?
Une fonction que tu définis sans lui donner de nom, généralement passée directement à une autre fonction : sapply(x, function(v) v^2). Depuis R 4.1 il existe aussi le raccourci \(v) v^2, qui signifie exactement la même chose avec moins de frappes.