A beginner friendly intro to functional programming
Functional programming is a highly valued approach to writing code, and it’s popularity is continuously increasing in applications logicielles commerciales. La programmation fonctionnelle est un paradigme d’écriture de code et est présentée avec éloquence dans l’introduction de cet article de Wikipedia:
» – un style de construction de la structure et des éléments des programmes informatiques – qui traite le calcul comme l’évaluation de fonctions mathématiques et évite les données à état changeant et mutables. C’est un paradigme de programmation déclarative, ce qui signifie que la programmation se fait avec des expressions ou des déclarations au lieu d’instructions. »
Nous allons entrer dans ce que cela signifie exactement très bientôt, mais d’abord, éliminons les fondamentaux en fournissant un contexte. Cet article a pour but, espérons-le, de vous présenter les concepts fondamentaux de la programmation fonctionnelle et à la fin de celui-ci, nous aurions établi une compréhension de base des raisons pour lesquelles nous choisirions de l’appliquer à nos styles de codage, comment cela se rapporte à JavaScript et quelques modèles de base que vous pouvez commencer à implémenter dans votre code. Soyez à l’affût d’un deuxième article qui s’appuiera sur celui-ci et approfondira encore plus les idées discutées ici.
Les racines de la programmation fonctionnelle se trouvent dans le Lambda calculus, qui était un système développé dans les années 1930 pour exprimer le calcul en utilisant des fonctions similaires à ce que nous verrons très bientôt. Pendant un certain temps, les concepts et langages de programmation fonctionnelle ont été largement discutés dans les milieux universitaires et universitaires et ont fini par se fondre dans le développement de logiciels commerciaux. Ce qui rend un langage de programmation fonctionnel ou non, c’est sa capacité à faciliter le paradigme de programmation fonctionnelle, des langages comme Ruby, Python, Julia et JavaScript, ce dernier ayant des propriétés de paradigmes impératifs, orientés objet et fonctionnels.
Regardons un exemple d’utilisation d’un impératif, puis d’une approche fonctionnelle pour terminer une seule tâche.
Impératif:
const arr = function getOdds(arr){
let odds = ; for(let i = 0; i < arr.length + 1; i++){
if ( i % 2 !== 0 ){
odds.push( i )
};
};
return odds
};console.log(getOdds(arr))
// logs
Fonctionnel:
function getOdds2(arr){
return arr.filter(num => num % 2 !== 0)
}console.log(getOdds2(arr))
// logs // this can be even shorter
const getOdds3 = arr => arr.filter(num => num % 2 !== 0)console.log(getOdds3(arr))
// logs
Outre les améliorations évidentes apportées par l’approche fonctionnelle, comme un code plus court, nous permettant d’économiser quelques frappes, et le fait qu’il soit beaucoup plus facile à comprendre d’un coup d’œil rapide, il est également élégant, ce qui se traduit par un code plus propre, simplifie le débogage, les tests et la maintenance.
Décomposons un peu cela, afin que nous puissions comprendre clairement les différences entre les deux approches et définir ce qu’est la programmation fonctionnelle.
Dans la première approche, nous décrivons impérativement chaque événement qui doit avoir lieu pour que nous puissions accomplir la tâche de filtrer les nombres impairs d’un tableau. Nous alimentons une fonction un tableau, à l’intérieur de la fonction, nous créons un tableau vide que nous utiliserons pour stocker les nombres impairs. Nous lui disons de faire une boucle sur le tableau, puis nous déclarons un conditionnel, si l’index actuel est un nombre impair, poussez-le vers le nombre vide. La boucle for n’inclut pas le dernier numéro du tableau, elle n’inclut que les numéros qui y mènent, donc si notre dernier numéro est impair, il ne sera pas inclus. Par conséquent, nous ajoutons +1 lors de la définition de la quantité d’itérations que notre boucle doit effectuer.
Dans la deuxième approche, nous définissons simplement le résultat que nous voulons voir en utilisant une méthode appelée filtre, et permettons à la machine de s’occuper de toutes les étapes entre les deux. Il s’agit d’une approche plus déclarative. Nous déclarons ce que le résultat final doit être, et nous le reste est géré pour nous.
Maintenant, nous pouvons voir ce que la définition mentionnée ci-dessus s’efforce d’exprimer. Une façon de programmer, en utilisant des déclarations et des expressions, plutôt que des instructions. Cette définition ne fait que gratter la surface de la programmation fonctionnelle, et nous allons continuellement nous appuyer sur notre définition à mesure que notre compréhension grandit.
Quelques différences entre les approches itératives et fonctionnelles.
- Stylistiquement, nous définissons un problème et les changements que nous aimerions voir, plutôt que de l’expliquer étape par étape.
- Nous n’avons pas besoin de gérer l’état dans nos fonctions comme ci-dessus où nous avons géré l’état de notre tableau vide.
- Nous n’avons pas à nous soucier autant de l’ordre d’exécution.
- Nous utilisons moins de boucles, de conditions et utilisons plus de méthodes intégrées, de fonctions réutilisables et de récursivité.
En utilisant cette approche, nous écrivons finalement du code plus propre qui, comme mentionné ci-dessus, nous aide au débogage et à la maintenance. Il garde les choses modulaires, et les sections de notre code sont décomposées en plus petits morceaux que nous pouvons tester facilement. Nous pouvons réutiliser des parties de notre code en utilisant des fonctions d’assistance et enfin, c’est une approche mathématique plus efficace pour écrire du code.
Les Piliers: Notre boîte à outils de codage pour l’écriture de code fonctionnel
Voici quelques aspects importants de l’écriture de code fonctionnel de haute qualité. Vu qu’il s’agit d’un aperçu, nous ne plongerons pas trop dans chacun d’eux, mais nous définirons simplement quelques caractéristiques clés et un exemple de chacun.
Fonctions pures :
Les fonctions pures renvoient une valeur uniquement basée sur ce qui y a été transmis. L’idée derrière cela est que ce sera une fonction pure si elle renvoie toujours le même résultat si les mêmes valeurs lui sont transmises, et qu’elle ne modifie pas les valeurs en dehors de la portée ts, ce qui la rend indépendante de tout état du système. Par conséquent, une fonction pure ne peut jamais muter des données, ne produire aucun effet secondaire et peut être facilement réutilisée. Un exemple de fonction non pure sera une fonction qui effectue un appel d’API ou renvoie un résultat imprévisible.
Fonction Impure simple:
var tip = 0;function calculateTip( mealTotal ) {
tip = 0.15 * mealTotal;
}calculateTip( 150 )
console.log(tip)
Fonction Pure simple:
function isPure(x,y) {
return x * y
}console.log(isPure(3,5));
La fonction pure renverra le résultat exact à chaque fois, et elle ne mute aucune donnée en dehors de celle-ci. La chose importante à laquelle il faut faire attention est qu’une fonction pure doit rester à l’écart de la mutation de données, alors soyez prudent lorsque vous sélectionnez les méthodes à utiliser dans vos fonctions pures. Par exemple, si vous souhaitez fusionner deux tableaux à l’intérieur de votre fonction, comme on le ferait généralement dans un réducteur React, évitez d’utiliser le tableau.prototype.méthode push(). Au lieu de cela, vous voudriez utiliser un tableau.prototype.concat(), qui conservera l’état des anciens tableaux et en retournera un nouveau pour votre usage.
Fonctions d’ordre supérieur:
En Javascript, les fonctions sont traitées comme des objets, nous pouvons donc passer des fonctions comme nous le ferions pour toute autre valeur. Une fonction d’ordre supérieur est simplement une fonction qui fonctionne sur d’autres fonctions. Ils peuvent prendre une fonction en entrée ou en renvoyer une en sortie. Nous verrons un exemple simple dans la démonstration suivante.
Fonctions anonymes:
Les fonctions anonymes sont très utiles lorsque nous devons définir une logique ad hoc selon nos besoins. Comme son nom l’indique, une fonction anonyme dans nameless, et principalement trouvée comme argument d’une fonction en remplacement d’une fonction nommée, une fonction assignée à une variable ou renvoyée en tant que fonction dans une fonction d’ordre supérieur. Ses racines se trouvent fortement dans le Lambda calcul et sont très importantes pour tous les langages de programmation fonctionnels.
Fonction anonyme affectée à une variable. Facile à passer et à invoquer en cas de besoin.
const myVar = function(){console.log(‘Anonymous function here!’)}myVar()
Fonction anonyme en argument
setInterval(function(){console.log(new Date().getTime())}, 1000);
Fonctions anonymes dans une fonction d’ordre supérieur
function mealCall(meal){
return function(message){
return console.log(message + " " + meal + ‘!!’)
}
}const announceDinner = mealCall(‘dinner’)
const announceLunch = mealCall(‘breakfast’)announceDinner(‘hey!, come and get your’)
announceLunch(‘Rise and shine! time for’)
Récursivité
La récursivité est une technique de programmation fonctionnelle bien connue. Une fonction récursive est simplement une fonction qui s’appelle elle-même et agit donc comme une boucle exécutant le même code plusieurs fois. Il est livré avec une mise en garde cependant, il faut faire attention à éviter les récursions infinies. Par conséquent, un cas de base est nécessaire pour lui dire quand s’arrêter. Les fonctions ou algorithmes récursifs peuvent tous deux être implémentés en utilisant la récursivité et les boucles, mais il est préférable d’utiliser la récursivité. Voici l’algorithme bien connu pour factoriser un nombre à la fois en utilisant la récursivité et une boucle.
Fonction récursive
function factorialize(num){
if (num === 0 || num === 1){return 1;}
return (num * factorialize(num — 1));
}var result = factorialize(14);console.log(result);
Récursivité à l’aide d’une boucle
function factorialize(num) {
if (num === 0 || num === 1){
return 1;
}
for (var i = num-1; i >= 1; i-- ) {
num *= i;
}
return num;
}
console.log(factorialize(6));
Nous avons couvert quelques-uns des ingrédients essentiels à l’écriture de code fonctionnel. Il n’est pas toujours possible d’écrire du code fonctionnel dans une application, mais les avantages sont grands lorsqu’ils sont utilisés autant que possible. Les frameworks comme Angular et React sont fortement influencés par la programmation fonctionnelle, et des bibliothèques comme Redux et Lodash nous permettent d’en utiliser les avantages, il y a donc certainement un grand avantage à commencer à penser à la manière FP.
Ressources pour en savoir plus ? Voici quelques excellents articles et ressources pour un apprentissage ultérieur.
- Pourquoi apprendre la programmation fonctionnelle en JavaScript ? par Eric Elliot
- Javascript éloquent par Marijn Haverbeke
- Donc vous voulez être un programmeur fonctionnel par Charles Scalfani
J’espère vraiment que cela a été utile et dans le prochain article, nous plongerons un peu plus en profondeur et déballerons des outils encore plus intéressants et utiles comme les méthodes JavaScript, l’application partielle, le curying, la liaison d’arguments et plus encore.
N’hésitez pas à applaudir, partager, critiquer ou partager vos réflexions sur le sujet!