La programmation fonctionnelle expliquée simplement
La programmation fonctionnelle intimide souvent par son vocabulaire — monades, foncteurs, currying — au point de masquer une idée simple et puissante : construire un programme en composant des fonctions, comme on assemble des briques, plutôt qu’en manipulant un état qui change au fil du temps. Ce paradigme n’est pas réservé à des langages exotiques : vous en faites probablement déjà en JavaScript ou en Python sans le nommer. Décortiquons ses concepts clés, un par un.
Les fonctions pures
C’est la pierre angulaire. Une fonction pure respecte deux règles :
- pour les mêmes arguments, elle renvoie toujours le même résultat ;
- elle ne provoque aucun effet de bord (elle ne modifie rien en dehors d’elle-même).
// Pure : dépend uniquement de ses arguments
function tva(prix) {
return prix * 1.2;
}
// Impure : dépend d'une variable externe et la lit
let taux = 1.2;
function tvaImpure(prix) {
return prix * taux; // le résultat change si `taux` change ailleurs
}
Une fonction pure est un délice à tester (pas de contexte à préparer), à mettre en cache et à raisonner : on peut la comprendre isolément, sans se demander « et si l’état global avait changé ? ».
L’immuabilité
Dans un style fonctionnel, on ne modifie pas les données : on en crée de nouvelles versions. Plutôt que de changer un tableau en place, on en produit une copie transformée. Cela élimine toute une catégorie de bugs où deux parties du code partagent la même donnée mutable sans le savoir.
const nombres = [1, 2, 3];
// Impératif : on mute le tableau original
// nombres.push(4);
// Fonctionnel : on crée un nouveau tableau, l'original est intact
const augmente = [...nombres, 4];
En Python, on privilégiera de même les tuples ou des reconstructions plutôt que la mutation en place quand la clarté prime.
Les fonctions d’ordre supérieur
Une fonction d’ordre supérieur prend une fonction en argument, en renvoie une, ou les deux. C’est ce qui rend la composition possible — et c’est déjà partout dans le code du quotidien. En JavaScript, map, filter et reduce en sont les exemples emblématiques :
const nombres = [1, 2, 3, 4, 5, 6];
const pairs = nombres
.filter((n) => n % 2 === 0) // garde les pairs
.map((n) => n * n); // les élève au carré
// pairs = [4, 16, 36]
const somme = nombres.reduce((acc, n) => acc + n, 0);
// somme = 21
En Python, on retrouve map, filter et les compréhensions de listes qui expriment la même idée de transformation déclarative :
nombres = [1, 2, 3, 4, 5, 6]
carres_pairs = [n * n for n in nombres if n % 2 == 0]
# [4, 16, 36]
On décrit quoi obtenir (les carrés des pairs) plutôt que comment boucler pour l’obtenir. Ce style déclaratif rejoint des habitudes utiles quel que soit votre langage principal, comme on le voit dans notre comparatif Python vs JavaScript.
La récursivité
Sans variable de boucle mutable, la répétition s’exprime naturellement par la récursivité : une fonction qui s’appelle elle-même sur un sous-problème plus petit, jusqu’à un cas de base.
def factorielle(n):
if n <= 1: # cas de base
return 1
return n * factorielle(n - 1) # cas récursif
La récursivité est élégante pour les structures naturellement récursives (arbres, listes). Attention toutefois : en Python et en JavaScript, une récursion trop profonde peut saturer la pile d’appels. Certains langages fonctionnels optimisent l’appel terminal (tail call) pour éviter ce problème ; ce n’est pas garanti partout.
Maîtriser les effets de bord
Un programme utile doit bien finir par agir sur le monde : afficher, écrire un fichier, appeler une API. La programmation fonctionnelle ne les interdit pas — elle cherche à les isoler. L’idée : concentrer la logique dans des fonctions pures, faciles à tester, et repousser les effets de bord aux frontières du programme (l’entrée/sortie). Le cœur reste prévisible ; seuls les bords touchent au monde extérieur.
Un clin d’œil aux langages fonctionnels
JavaScript et Python permettent le style fonctionnel, mais des langages sont conçus pour lui. OCaml et Haskell poussent la logique jusqu’au bout : immuabilité par défaut, système de types puissant, fonctions pures encouragées ou imposées. Haskell est même dit purement fonctionnel : les effets de bord y sont explicitement modélisés dans le système de types. Les explorer, même sans les adopter, affûte durablement la façon de penser le code.
(* En OCaml : une fonction d'ordre supérieur idiomatique *)
let carres_pairs = List.filter_map
(fun n -> if n mod 2 = 0 then Some (n * n) else None)
[1; 2; 3; 4; 5; 6]
(* [4; 16; 36] *)
En pratique : pourquoi s’y mettre
Vous n’avez pas à réécrire vos projets en Haskell pour en tirer profit. Adopter quelques principes — préférer les fonctions pures, éviter la mutation partagée, utiliser map/filter/reduce plutôt que des boucles à état — rend le code plus court, plus testable et plus facile à raisonner. La programmation fonctionnelle n’est pas une religion opposée à l’objet ou à l’impératif : c’est une boîte à outils mentale qui coexiste très bien avec vos habitudes actuelles.
À lire ensuite
- Python vs JavaScript — deux langages qui embrassent tous deux le style fonctionnel
- Apprendre Python — pour pratiquer les compréhensions et fonctions d’ordre supérieur
- Rust vs C++ — comment Rust intègre des idées venues du monde fonctionnel