Lise Vaudor
31/03/2022
La programmation doit vous permettre d’automatiser un certain nombre de traitements avec R, i.e. de décrire un certain nombre d’opérations similaires et les faire exécuter en lot par la machine.
La programmation fonctionnelle est une manière de réaliser cette automatisation des traitements, en raisonnant principalement sur l’écriture et l’utilisation des fonctions comme “unités opérationnelles”.
Ainsi, pour schématiser ce principe, il s’agit en fait d’identifier ce qui dans le code est commun au différentes itérations (ici en gris) et les éléments qui varient d’une fois à l’autre (en jaune bleu rose à gauche) et qui vont correspondre à l’argument (ou aux différents arguments) de la fonction à droite (en orange). Typiquement, on recommande de créer une fonction (au lieu d’écrire plusieurs fois des lignes de code identiques à un ou deux détails près) dès que l’on souhaite réaliser au moins 3 opérations similaires. |
Une fonction s’écrit de la manière suivante: On définit ainsi plusieurs choses:
|
Par exemple, la fonction convertit les températures en degrés Fahrenheit, en températures en degrés Celsius. On peut par exemple la tester de cette manière:
|
Testons cette fonction:
|
Voilà comment on peut voir une fonction… |
Ici je considère une fonction Classiquement, on va produire l’output en appelant la fonction avec pour arguments l’input Par exemple: Ici, j’ai produit l’outputmoyenne en appelant la fonction mean() , avec pour argument principal x et pour argument secondaire na.rm=TRUE .
|
Les instructions conditionnelles (if ou if else) permettent d’exécuter (ou non) certaines commandes en fonction de conditions spécifiées par l’utilisateur. Voici la structure d’une instruction conditionnelle if. Le principe est que les lignes de codes (symbolisées par La structure if else permet de préciser ce qui se passe dans le cas contraire (quand la condition n’est pas vérifiée): Exemples: |
Il ne se passe rien, car la condition n’étant pas remplie la commande
Ici au contraire, la condition ( |
On peut également réaliser des opérations en boucle à l’aide d’une structure de contrôle Les boucles for permettent d’exécuter des instructions de manière itérative (ou répétée). Voici la structure d’une instruction instruction for: Par exemple:
|
On fait varier le compteur (ici appelé C’est un principe qui vous dit quelque chose?… Eh oui, c’est quelque chose qu’on pourrait faire en transformant l’ensemble d’instructions en fonction, et en faisant en sorte d’appliquer cette fonction à l’ensemble des éléments variants. D’ailleurs, dans le cadre de la programmation fonctionnelle, on n’utilise pas trop de boucles for, on utilise plutôt les fonctions du package purrr! |
Ainsi, en utilisant |
Mon argument principal, moyennes est par défaut également une liste.
|
Notez que l’on aurait pu ici demander explicitement à ce que le résultat nous soit renvoyé non pas comme une liste, mais comme un vecteur de valeurs numériques de type “double”:
Selon le type d’output renvoyé par la fonction, il peut ainsi être assez pratique d’utiliser les fonctions
|
Considérons maintenant les effets secondaires, en prenant pour exemple une fonction dont l’utilité première n’est pas de renvoyer un output, mais plutôt d’afficher quelque chose dans la console: |
Reprenons notre exemple La fonction “walk()” permet d’itérer les “effets secondaires” d’une fonction… ici 3 messages/nuages de fumée différents:
|
safely()
Jusqu’ici, tout va bien: j’ai choisi pour commencer des exemples d’application simples, où tout se déroule comme sur des roulettes. Mais avec les fonctions de |
Considérons ainsi l’exemple suivant:
Aïe… La fonction |
safely()
Pour remédier à cela, outre modifier la fonction
|
Dans ce cas, pour chaque élément d’input, on obtient un élément d’output qui contient deux choses:
|
Comment intégrer l’usage de purrr dans la manipulation de tableaux avec purrr? Principalement en combinant Voici un exemple, où l’on utilise la fonction emo::ji() pour transformer des mots en emojis (=des caractères spéciaux).
|
Voici comment procéder:
On a ici produit une table contenant une “colonne liste” (ou list-column). Voyez plutôt:
|
Dans le cas illustré dans la diapositive précédente, le fait que la nouvelle colonne soit une liste plutôt qu’un vecteur ordinaire est plus une gêne qu’autre chose… De fait, nous aurions mieux fait d’utiliser
|
Attention, notez bien la différence de syntaxe:
cherche à extraire un élément appelé “pouetpouet” des différents éléments de la liste x
.
En revanche
cherche à appliquer une fonction appelée pouetpouet
aux différents éléments de la liste x
.
En utilisant mutate + map + une fonction qui produisait un jeu de données de taille variable en sortie, on avait produit une nested tibble (qu’on avait ré-aplati à l’aide de tidyr::unnest()
).
On peut aussi être amené à vouloir produire une nested tibble pour itérer une fonction via map, si la fonction qu’on veut appliquer doit avoir pour entrée principale un jeu de données. Dans ce cas on peut utiliser la fonction |
|