.. _functions: Les fonctions ============= R permet la création d'objets ``function``, que l'on peut affecter à des variables pour réutilisation ultérieure. La structuration du code en fonctions élémentaires permet un gain de productivité et de lisibilité. Chaque fois qu'une portion de code doit être exécuté plusieurs fois avec seulement un changement de paramètres, on écrira une fonction. .. warning:: Il y a débat pour savoir si le terme "plusieurs" fait référence à 2 instructions et plus, ou s'il est plus efficace de copier/coller/modifier la ligne de code lorsque deux instructions semblables sont répétées. Il n'y a aucune ambigüité pour 3 instructions semblables. R met en oeuvre le paradigme de `programmation fonctionnelle `_. La plupart des fonctions de R Core sont elle mêmes écrites en R. C'est le cas de :func:`mean` et :func:`var` par exemple. Elle sont de ce point de vue tout à fait semblables aux fonctions écrites par l'utilisateur. On définit une fonction avec l'instruction suivante:: > name <- function(arg_1, arg_2, …) expr ``expr`` est une expression R, généralement une expression groupée. Les ``arg_i`` sont les arguments de cette fonction qui doivent être passés en paramètre lors de l'appel. La valeur de retour de la fonction est l'évaluation de ``expr``. L'appel de la fonction prend la forme ``name(par_1, par_2, ...)``. Un exemple ---------- Une implémentation de la suite de Fibonacci peut être écrite de façon récursive:: fib_r <- function(n,a=1,b=1){ if (n == 1) a else fib(n-1,b,a+b) } > fib_r(32) [1] 2178309 ou itérative:: fib_i <- function(n) { if (n == 1) 1 else if (n == 2) 1 else { f <- c(1,1) for (i in 3:n) f <- c(0,f[1]) + f[2] f[2] } } > fib_i(32) [1] 2178309 Définir des opérateurs binaires ------------------------------- Pour simplifier l'écriture et augmenter la lisibilité, on peut affecter un opérateur à une fonction. Si on choisit le caractère ``!``, on définira la fonction de la façon suivanteas:: > "%!%" <- function(x, y) expr On utilisera l'opérateur de la façon suivante:: > x %!% y ce qui sera strictement identique à:: > f(x,y) A titre d'exemple, R core utilise l'opérateur ``%*%`` pour la multiplication de matrices. **Tidyverse** utilise le pipe ``%>%`` pour chainer les opérations. Arguments nommés et par défaut ------------------------------ On a déjà utilisé les arguments nommés lors de l'appel à certaines fonctions. En particulier, ``na.rm=TRUE`` est utilisé avec les fonction statistiques (:func:`mean` par exemple) pour écarter les ``NA`` avant traitement. Les arguments nommés peuvent être fournis lors de l'appel dans n'importe quelle position. Les arguments nommés sont placés après les arguments positionnels. On considère la fonction :func:`fun1` définie par:: > fun1 <- function(data, data.frame, graph, limit) { [function body omitted] } La fonction :func:`fun1` peut être appelée de différentes manières:: > ans <- fun1(d, df, TRUE, 20) > ans <- fun1(d, df, graph=TRUE, limit=20) > ans <- fun1(data=d, limit=20, graph=TRUE, data.frame=df) Il est souvent pratique de fournir des valeurs par défaut pour certains arguments. C'est le cas pour la fonction :func:`mean` pour laquelle la valeur par défaut de l'argument ``na.rm`` est ``FALSE``:: > mean(c(1:10,NA,11:20)) [1] NA > mean(c(1:10,NA,11:20), na.rm=TRUE) [1] 10.5 Dans la plupart des cas, les arguments possèdent des valeurs par défaut et il n'est alors pas utile de les passer explicitement. Si on déinit la fonction :func:`fun1` par:: > fun1 <- function(data, data.frame, graph=TRUE, limit=20) { … } si on veut l'appeler avec les paramètres par défaut, on utilisera l'instruction:: > ans <- fun1(d, df) On peut également forcer la valeur d'un paramètre par défaut:: > ans <- fun1(d, df, limit=10) Les valeurs par défaut ne sont pas obligatoirement des constantes. Ce peut également être des expressions impliquant d'autres arguments de la fonction. .. _...: L'ellipsis ``...`` ------------------ Pour une utilisation optimale de fonctions, il faut pouvoir: #. pouvoir passer un nombre arbitraire de paramètres #. passer des paramètres à une fonction appelée dans le corps de la définition de la fonction appelante On utilise pour cela un argument spécial appelé ``ellipsis`` : ``...`` La fonction de création de vecteur est un exemple de fonction acceptant un nombre arbitraire de paramètres:: > c(1,2,3) [1] 1 2 3 > c("a", "b") [1] "a" "b" Si on jette un oeil à la `documentation de la fonction `_ :func:`c`, son premier argument est l'ellipsis. Pour illustrer le second cas, on considère la fonction :func:`addPercent`:: addPercent <- function(x, mult = 1, ...) { round(x * (1+mult/100), ...) } Dans ce premier appel, on n'utilise pas d'arguments supplémentaires, l'ellipsis ne capture donc rien, et les arguments par défaut de round sont utilisés (``digits=0``):: > addPercent(n, 3.45) [1] 10 21 31 41 52 Dans le deuxième appel, l'argument supplémentaire ``digits=2`` est capturé par l'ellipsis ``...`` et est passé à la fonction :func:`round`:: > addPercent(n, 3.45, digits=2) [1] 10.34 20.69 31.04 41.38 51.73 Les paramètres capturés par l'ellipsis sont stockés dans une ``list`` et peuvent être référencés indépendamment dans le corps de la fonction. Variables locales et globales ----------------------------- L'opérateur d'affection traditionnel ``<-`` utilisé dans le corps de la fonction déclare des variables **locales**. Pour donner une portée **globale** à une variable, on utilise un autre opérateur d'affectation ``<<-``:: f <- function(n){ v1 <- n+1 # variable locale v2 <<- n+1 # variable globale n+1 } > f(3) [1] 4 > v1 Error: object 'v1' not found > v2 [1] 4