Programmation fonctionnelle

icône de pdf
Signaler

Le paradigme fonctionnel offre un excellent modèle de décomposition d’un problème. Il est adapté aux besoins modernes des machines multi-processeurs et a pour but de se rapprocher du mode de pensée humain.

I) La programmation fonctionnelle

La programmation fonctionnelle est née en même temps que la programmation impérative (Lisp dans les années 1950) mais est longtemps restée marginale, plus académique qu’industrielle (langages ML et dérivés, Haskell). Cependant, la plupart des langages apparus au XXIe siècle sont fortement influencés par un style fonctionnel. Python, par exemple, dans sa version 3.10 (PEP 622) propose le filtrage par motif structurel qui est un des points forts de la programmation fonctionnelle. Après d’autres introductions fonctionnelles, c’est le signe que les frontières s’estompent entre paradigmes de programmation.

Des entreprises comme Google (avec Go), Mozilla (avec Rust), Android (avec Kotlin), Apple (avec Swift), Whatsapp (avec Erlang), Tweeter (avec Scala) entre autres ont lancé ou utilisent de nouveaux langages qui ont intégré de nombreux aspects de la programmation fonctionnelle notamment pour faciliter le traitement de gros flux de données et la programmation concurrente, car ce n’est plus tant la puissance des processeurs qui évolue, mais leur nombre, et la possibilité de travailler avec des logiciels en ligne (SaaS : software as a service).

II) Caractéristiques de la programmation fonctionnelle

Non pas « comment ? » mais « quoi ? »

En programmation fonctionnelle, on déclare ce que l’on veut faire mais pas comment cela va être fait : un programme consiste essentiellement à décrire le rapport qui existe entre les données et les résultats que l’on veut obtenir, plutôt que la séquence de traitements qui mène des unes aux autres.

Exemple : Quelle est la somme des 100 premiers entiers naturels pairs tels que le carré de la somme d’un de ces nombres additionné à 2 est divisible par 137 ? Voici comment cela peut être programmé en Haskell :

sum <span>take<span><span>100</span><span><span> <span>take <span><span>100</span> <span><span> filter (\x -> (x + 2)^2 `mod` 137 == 0) [0,2..]

Dans cet exemple, on compose des fonctions dont le nom permet de comprendre le rôle.

La transparence référentielle

En programmation fonctionnelle, il n’y a pas d’affectation. Lorsqu’on écrit a = 1, a peut être remplacé par 1 tout au long du programme.

Idempotence

Vous obtenez toujours le même résultat pour chaque appel d’une fonction. Il faut donc éviter au maximum les variables globales et les fonctions à effets secondaires.

Concurrence et/ou parallélisation

L’idempotence et la transparence référentielle permettent aux langages modernes de gérer efficacement la concurrence si importante actuellement. On peut en effet se libérer de contraintes de chronologie. Par exemple si res = f1(a,b) + f2(a,c), on peut effectuer les appels à f1 et f2 à n’importe quel moment car a ne sera pas modifié.

Pas d’affectation : des liens !

C’est une conséquence de la transparence référentielle. Une expression est liée à une valeur. Si on veut changer cette valeur, il faut créer une autre expression.

Remarque

Ou encore : « Ne modifiez pas ! Créez ! »

On peut s’en inspirer en Python aussi.

Ainsi, au lieu de :

2f09daf3-56d6-473e-b19c-739baddfefd6

on préférera :

69df88fb-eb17-4d5c-aa4c-7c8f2239e2d5

Récursion

Sans affectations ni boucles, la programmation fonctionnelle passe souvent par des définitions récursives de fonctions, c’est-à-dire des fonctions qui s’appellent elles-mêmes.

Les fonctions sont des objets comme les autres

Les fonctions peuvent prendre d’autres fonctions en argument. Supposons que nous voulions filtrer des listes selon des critères changeants. On peut utiliser l’opérateur lambda qui permet de créer des fonctions selon la syntaxe :

42b9c3c7-007a-4ec2-897d-87284acb64db

Par exemple, pour créer « à la volée » la fonction x2x+1 :

c79ab30d-342f-4423-a511-b065eba5fff1

On peut le lire ainsi : « Une fonction qui prend x en paramètre et renvoie 2*x + 1. »

Dans le cas d’un filtre :

acf2082f-5638-4563-9cbc-d8a940d4e054

Par exemple pour obtenir les nombres pairs et positifs d’une liste d’entiers :

a7064353-e739-4546-9b54-3b011615a335