La programmation fonctionnelle expliquée en 5 minutes [With Examples]

Photo of author

By pierre



La conception d’un logiciel est une entreprise complexe et technique, exigeant une planification minutieuse et une approche stratégique pour identifier la solution idéale à un problème donné à l’aide de la programmation.

Dans cette perspective, le choix d’un paradigme de programmation adapté avant de se lancer dans le développement est une étape cruciale.

Un paradigme de programmation est en fait un modèle, une manière spécifique d’aborder la programmation. Il propose des outils, des schémas, des principes, des règles ainsi que des styles pour la conception, la structuration et l’écriture des programmes informatiques.

Parmi les paradigmes de programmation les plus connus, on trouve la programmation orientée objet (POO), la programmation procédurale, la programmation événementielle et la programmation fonctionnelle, entre autres.

La programmation fonctionnelle, en particulier, a suscité un intérêt considérable dernièrement en raison de sa promesse de codes moins bogués, hautement réutilisables et faciles à maintenir. Mais qu’est-ce que la programmation fonctionnelle exactement?

La programmation fonctionnelle est un sous-ensemble du paradigme de programmation déclarative. La programmation déclarative se concentre sur l’écriture d’un code qui décrit ce qu’un programme doit accomplir, plutôt que de spécifier comment il doit le faire.

Un exemple concret de cette approche est l’interrogation de bases de données SQL. Au lieu de détailler précisément la méthode de récupération des données, on se contente de préciser les informations que l’on souhaite obtenir.

La programmation fonctionnelle elle-même est une méthode de création de programmes informatiques, utilisant des expressions et des fonctions pures appliquées séquentiellement pour résoudre des problèmes ou atteindre les résultats souhaités.

En programmation fonctionnelle, la totalité des fonctionnalités d’un programme est divisée en fonctions pures, réutilisables et dédiées à une tâche spécifique. Chaque aspect du programme passe par l’utilisation de ces fonctions pures.

Une fonction pure est déterministe : pour les mêmes entrées, elle produira toujours la même sortie et n’aura pas d’impact sur d’autres parties de l’application.

Le résultat d’une fonction pure dépend uniquement de ses entrées et non pas d’une variable globale au sein de l’application qui pourrait en influencer le résultat.

Ces fonctions pures reçoivent des données en entrée, les traitent localement et génèrent une sortie sans altérer d’autres sections du programme.

La programmation fonctionnelle repose sur des données immuables, c’est-à-dire qu’elles ne peuvent être modifiées une fois créées. Elle évite également les états partagés, où les mêmes données peuvent être consultées et modifiées par différents segments du programme.

Étant donné l’importance des fonctions en programmation fonctionnelle, ces dernières sont considérées comme des citoyens de première classe : elles peuvent être passées en argument, enregistrées dans une variable ou encore renvoyées par une autre fonction.

De plus, la programmation fonctionnelle s’appuie davantage sur les expressions que sur les instructions, évitant ainsi les boucles telles que « for » et « while ». Cela permet de rendre la logique du programme plus facile à suivre et à déboguer.

Types de langages de programmation fonctionnelle

Il existe deux grandes catégories de langages de programmation fonctionnelle :

  • Langages purement fonctionnels : Ces langages soutiennent, appliquent et favorisent l’utilisation de paradigmes fonctionnels, tels que l’emploi de fonctions pures de première classe, l’immuabilité des états et des données, et des fonctions sans effets secondaires sur d’autres parties du programme. Des exemples incluent Haskell, Agda, Clean, Idris, Futhark et Elm.
  • Langages fonctionnels impurs : Ces langages prennent en charge les principes de la programmation fonctionnelle, mais autorisent également l’utilisation de fonctions impures, des mutations de l’état d’un programme et des opérations ayant des effets secondaires. On peut citer Javascript, Rust, Erlang, Python, Ruby, Java, Kotlin et Clojure.

Les développeurs utilisent à la fois des langages purement fonctionnels et impurs. Cependant, la transition vers un langage purement fonctionnel peut être complexe et prendre du temps pour les personnes non familières avec la programmation fonctionnelle.

Langages de programmation fonctionnels et bibliothèques

Voici quelques exemples de langages et de bibliothèques fonctionnels populaires :

#1. Haskell

Haskell est un langage de programmation purement fonctionnel, statiquement typé et paresseux, considéré comme l’incarnation du paradigme de la programmation fonctionnelle.

Outre l’inférence de type, Haskell prend en charge l’évaluation paresseuse, où les expressions ne sont évaluées que lorsque leurs résultats sont nécessaires. Il offre également la possibilité de programmation concurrente, et sa compilation intègre un ramasse-miettes performant ainsi qu’une bibliothèque de concurrence légère.

Grâce à son adhésion rigoureuse aux principes de la programmation fonctionnelle, Haskell facilite la création de systèmes logiciels complexes et en simplifie la maintenance.

Haskell est souvent le langage de prédilection pour la création de systèmes autonomes ou de langages spécifiques à un domaine. Il est également très utilisé dans le milieu universitaire et la recherche. Des entreprises comme Microsoft, Github, Hasura et Lumi font partie de celles qui utilisent Haskell.

#2. Ramda

Ramda est une bibliothèque de programmation fonctionnelle pour JavaScript. Elle simplifie la construction de logiques complexes grâce à la composition fonctionnelle et offre un ensemble de fonctions utilitaires qui encouragent et facilitent l’application des principes de programmation fonctionnelle en JavaScript.

Ramda permet également d’utiliser facilement des objets et des fonctions immuables sans effets secondaires, des concepts clés de la programmation fonctionnelle.

Bien que JavaScript ne soit pas un langage de programmation purement fonctionnel comme Haskell, l’utilisation d’une bibliothèque telle que Ramda permet de bénéficier des avantages de la programmation fonctionnelle tout en utilisant JavaScript.

#3. Élixir

Elixir est un langage de programmation fonctionnel, concurrent et généraliste, conçu pour être évolutif, facile à maintenir et tolérant aux pannes. Il a été créé en 2011 par Jose Valim, fonctionne sur la machine virtuelle BEAM et est utilisé par des entreprises telles que Heroku, Discord, change.org et Duffel.

En tant que langage de programmation fonctionnel, Elixir encourage l’immuabilité des états et des données, l’utilisation de fonctions pures lors de l’écriture du code et la transformation des données.

Concepts clés de la programmation fonctionnelle

#1. Fonctions pures

La programmation fonctionnelle s’appuie fortement sur les fonctions pures. Ces dernières possèdent deux caractéristiques majeures. Premièrement, elles produisent le même résultat pour une même entrée, quels que soient les facteurs externes, ce qui les rend déterministes et donc prévisibles.

Deuxièmement, les fonctions pures n’ont pas d’effets secondaires, c’est-à-dire qu’elles ne modifient pas l’environnement extérieur.

Voici quelques exemples de fonctions pures :

//function to calculate the square of a number
function square(x) {
    return x * x;
}

//function to add two variables
function add(a, b) {
    return a + b
}

Les fonctions ci-dessus renvoient la même sortie pour les mêmes entrées et n’ont aucun effet secondaire.

#2. Immutabilité

En programmation fonctionnelle, les données utilisées sont immuables, ce qui signifie qu’une fois les variables initialisées, elles ne peuvent plus être modifiées. Cela garantit la préservation de l’état d’une variable tout au long du programme.

Si vous souhaitez modifier une variable, il est possible de créer une nouvelle variable pour stocker les données mises à jour, sans modifier la variable initiale.

#3. Fonctions d’ordre supérieur

Les fonctions d’ordre supérieur sont celles qui acceptent une ou plusieurs fonctions comme arguments et/ou renvoient une fonction.

Elles sont essentielles en programmation fonctionnelle car elles permettent de combiner plusieurs fonctions pour créer de nouvelles fonctions, d’utiliser des rappels, d’abstraire des schémas communs en fonctions réutilisables et d’écrire un code plus concis et expressif.

Voici un exemple de fonction d’ordre supérieur :

// A higher-order function which returns a function that multiplies
// a number by a given factor
function multiplier(factor) {
    return function (number) {
      return number * factor;
    }
  }
  
const double = multiplier(2); 
const triple = multiplier(3);
const quadruple = multiplier(4);
  
console.log(double(5)); // Output: 10
console.log(triple(5)); // Output: 15
console.log(quadruple(5)); // Output: 20

#4. Récursivité

La programmation fonctionnelle s’appuyant sur des expressions plutôt que sur des instructions, les boucles « for » et « while » sont évitées. La récursivité remplace ces boucles pour réaliser des itérations.

La récursivité consiste en une fonction qui s’appelle elle-même plusieurs fois jusqu’à ce qu’une condition de sortie soit remplie. Un problème complexe est ainsi décomposé en sous-problèmes plus petits, résolus de manière récursive jusqu’à atteindre un cas de base qui fournit la solution au problème initial.

#5. Programmation déclarative

La programmation fonctionnelle est un sous-ensemble de la programmation déclarative, qui met l’accent sur la description de ce qui doit être fait plutôt que sur la manière de le faire.

Lorsqu’on adopte la programmation fonctionnelle, le code décrit ce qui doit être accompli ou le problème à résoudre. La manière d’y parvenir dépend du langage de programmation utilisé. Cela permet d’écrire un code plus concis et facile à lire.

#6. Sans état

La programmation fonctionnelle privilégie le code sans état, où le code ne conserve pas un état global pouvant être modifié par des fonctions. Les résultats des fonctions dépendent uniquement des entrées fournies, et ne sont pas influencés par des dépendances envers d’autres parties du code.

Les fonctions utilisées ne peuvent pas modifier un état ou une variable du programme en dehors de leur portée.

#7. Exécution parallèle

Étant donné l’utilisation d’états immuables, de fonctions pures et de données immuables, la programmation fonctionnelle permet l’exécution parallèle de plusieurs calculs simultanément.

Chaque fonction ne traitant qu’une entrée donnée, sans se soucier des effets secondaires des autres parties du programme, il est possible de diviser les problèmes complexes en sous-problèmes plus petits et de les exécuter simultanément pour améliorer les performances et l’efficacité.

Avantages de la programmation fonctionnelle

Voici quelques avantages de la programmation fonctionnelle :

Moins de bugs logiciels

En plus de rendre le code plus lisible et plus facile à comprendre grâce à l’utilisation de fonctions pures, la programmation fonctionnelle permet d’écrire du code avec moins d’erreurs.

Puisqu’elle utilise des états immuables, il n’y a pas de modification d’une variable ou de l’état du programme par plusieurs parties différentes. Cela réduit le risque d’erreurs dues à la modification de données depuis plusieurs zones en raison d’états partagés.

Améliore la lisibilité du code

La programmation fonctionnelle, étant une sous-catégorie de la programmation déclarative, met l’accent sur la description de ce qui doit être fait plutôt que sur la manière de le faire. Cette approche, associée à l’utilisation de fonctions pures, aboutit à un code plus explicite, facile à lire, à comprendre et à maintenir.

Améliorer la réutilisabilité du code

La mise en œuvre de la programmation fonctionnelle implique de décomposer les problèmes complexes en sous-problèmes plus petits et de les résoudre à l’aide de fonctions pures. Ces fonctions peuvent être facilement composées et réutilisées pour d’autres problèmes. L’utilisation de fonctions pures et d’états immuables permet d’écrire un code hautement réutilisable.

Test et débogage plus faciles

La programmation fonctionnelle utilise des fonctions pures qui n’ont pas d’effets secondaires, dépendent uniquement de leurs entrées et produisent des sorties déterministes pour un même ensemble d’entrées.

Cela rend la programmation fonctionnelle intrinsèquement facile à tester et à déboguer, car il n’est pas nécessaire de suivre une variable et son évolution dans différentes parties du programme.

L’absence de dépendances en programmation fonctionnelle facilite également le débogage et les tests, car on peut cibler des parties spécifiques d’un programme.

Prend en charge la concurrence et le parallélisme

La programmation fonctionnelle encourageant l’absence d’état et l’immuabilité des données, elle permet d’exécuter plusieurs fonctions pures en parallèle. La capacité d’exécuter plusieurs opérations en parallèle permet d’améliorer les vitesses de traitement et l’utilisation des processeurs multicœurs.

En tant que paradigme de programmation, la programmation fonctionnelle peut faciliter l’écriture d’un code plus lisible et compréhensible avec moins d’erreurs, et offre un excellent support pour le parallélisme permettant une utilisation efficace des processeurs multicœurs. Elle permet de créer des systèmes logiciels plus fiables et plus faciles à mettre à l’échelle.

Limites de la programmation fonctionnelle

Malgré ses nombreux avantages, la programmation fonctionnelle présente une courbe d’apprentissage qui exige un investissement de temps et d’efforts pour assimiler le paradigme, car il introduit de nouvelles façons de structurer le code et de nouveaux concepts de programmation.

Le codage en programmation fonctionnelle peut être extrêmement complexe et difficile, car elle ne fait pas appel à des fonctionnalités intuitives comme les boucles « for » et « while ». L’écriture de programmes de manière récursive n’est pas chose aisée.

Par conséquent, les développeurs peuvent prendre plus de temps à maîtriser la programmation fonctionnelle, en particulier lorsqu’ils viennent de langages qui utilisent des états mutables, comme dans la programmation orientée objet.

Une autre limitation provient de son principe fondamental d’immuabilité. Puisque les données et les états sont modifiables, et que de nouvelles structures de données sont créées au lieu de modifier celles qui existent, la programmation fonctionnelle peut utiliser plus d’espace de stockage. La nature immuable peut également entraîner une baisse des performances des applications.

Conclusion

Bien que la programmation fonctionnelle existe depuis longtemps, elle est devenue un paradigme de plus en plus populaire. Bien qu’elle puisse être un peu difficile à appréhender, l’apprentissage de ce paradigme et des différentes manières d’implémenter la programmation fonctionnelle peut s’avérer très bénéfique pour les développeurs.

Il n’est pas nécessaire d’utiliser des langages de programmation purement fonctionnels tels que Haskell ; il est possible d’implémenter des concepts de programmation fonctionnelle dans des langages comme Javascript, Java, Python et Kotlin et de profiter des avantages de la programmation fonctionnelle dans vos projets.

Il existe de nombreuses ressources pour apprendre Python pour les débutants.