Nous commençons par expliquer pourquoi apprendre la programmation fonctionnelle est pertinent pour un étudiant de licence.
Les langages fonctionnels proposent des types plus riches, permettant aux programmeurs d'exprimer exactement leurs besoins. Pour autant, la détection automatique des types par le compilateur permet de garder une syntaxe légere et un code concis. L'intégration de modules externes est facilité par la vérification rigoureuse des types, qui assument ainsi efficacement leur rôle de garde-fou contre l'écriture de programmes n'ayant pas de sens.
Avec la capacité d'utiliser des fonctions en argument d'autres fonctions, les programmeurs fonctionnels n'utilisent presque pas de boucles, simplifiant la structure des programmes et donc augmentant leur lisibilité. Le polymorphisme permet d'obtenir gratuitement du code générique, sans syntaxe additionnelle.
L'absence d'effets de bords (de modification de l'état du système, de la mémoire), permet de pouvoir comprendre le code de façon locale. Une fonction aura toujours le même comportement, quelque soit l'état du programme, son résultat ne dépend que des ses arguments. Il n'y a donc pas d'interactions complexes entre les différentes parties du programme, les seules dépendances sont complètement explicites : ce sont les appels de fonctions.
Les langages fonctionnels ne proposent pas l'affectation des variables. Une fois une variable initialisée, sa valeur ne pourra plus changer. C'est comparable au const de C. Ceci interdit bien des mauvaises habitudes, comme l'utilisation de variables globales ou de fonctions modifiant les variables d'une autre fonction.
Le typage statique du langage OCaml est très rigoureux. Impossible de faire une coercion de type quand cela nous arrange (par exemple vers void *), d'utiliser un pointeur nul, d'oublier les cas qu'on ne souhaite pas traiter par exemple. Nous sommes forcés d'être précis dans ce que nous programmons, car le compilateur ne nous laisse pas de liberté quand il s'agit d'écrire du code correct.
Les objets permettent d'encapsuler les effets dans des unités responsables de ces effets, ce qui permet d'augmenter la modularité, mais les objets entre eux peuvent potentiellement entretenir des relations complexes. Ceci incite à utiliser des patrons de conceptions permettant de limiter les interactions à des schémas simples, compréhensibles et extensibles.
En programmation fonctionnelle, il n'y a pas d'effet du tout. Chaque module peut donc se comprendre comme une entité indépendante, et comme les variables sont figées, il ne peut pas y avoir d'interaction complexe avec un morceau de code donc on ignore l'existence. Ceci permet de raisonner de façon locale à chaque module en réduisant drastiquement les erreurs potentielles.
Par ailleurs, la refactorisation est bien plus facile dans un langage fonctionnel statiquement typé comme Haskell ou OCaml. L'aspect fonctionnel permet de capturer au plus prêt les facteurs communs. Le typage offre des garanties fortes sur le fait que le programme reste correct au long de sa transformation.
Rien de plus simple qu'évaluer un programme fonctionnel : il suffit de remplacer chaque occurence de chaque variable par sa valeur. En répétant cette opération, on déplie un calcul. Pas besoin de faire intervenir un modèle complexe pour la mémoire : il n'y a pas de concept de mémoire en programmation fonctionnelle. Ce que vous avez sous les yeux, voilà votre code.
Nous listons maintenant plusieurs arguments que vous feriez mieux de ne pas avoir, si vous souhaitez ne pas être terriblement déçus, ainsi que des mauvais arguments contre la programmation fonctionnelle.
Combien de programmes avez-vous écrit sans utiliser une seule affectation, sans un seul tableau, sans boucle for ? En êtes-vous capable ? Il n'y a ni affectation, ni tableau, ni boucle en programmation fonctionnelle, il va donc probablement falloir changer vos habitudes.
Tout discours sur un langage de programmation qui vous promet la Lune sans effort est un mensonge, tout simplement. La programmation est une discipline complexe et exigeante, et la difficulté ne provient pas des langages mais bien des problèmes.
En revanche, les langages fonctionnels sont plus adaptés pour aborder certains problèmes. Dans ces cas, il devient plus simple d'exprimer les solutions que nous pouvons concevoir. Par contre la conception même de ces solutions restera toute aussi difficile qu'avec un autre paradigme (impératif, objet,...). C'est bien sûr aussi le cas des autres paradigmes avec d'autres problèmes, chaque paradigme possède ses forces et ses faiblesses, et avoir une bonne connaissance de chaque paradigme vous permettra de choisir le plus adapté à chaque problème.
C'est une opinion assez répandue, sur Internet notamment. On peut en effet faire des cours très mathématiques sur la programmation fonctionnelle et les liens avec la logique, et ce genre de cours semble avoir laissé des traces sur une génération d'étudiants. Ce n'est en tout cas pas du tout le point de vue adopté pour ce cours, dans lequel nous allons vraiment apprendre à utiliser un langage fonctionnel. Nous n'étudierons pas comment les langages fonctionnels sont conçus et comment ils fonctionnent, si ce n'est en fin de cours de manière assez superficielle, afin de prendre un peu de recul.
La part des langages fonctionnels dans l'industrie est effectivement assez négligeable, mais pas nulle pour autant, comme on peut le constater sur ces pages :
Les raisons qui font que tel ou tel langage prend de l'importance sont difficiles à cerner, mais tiennent probablement peu compte des qualités intrinsèques du langage lui-même (quelques facteurs de succès : les librairies, les outils de développement, le marketing, le support d'une grande entreprise garantissant la pérennité du langage).
On peut pratiquer la programmation fonctionnelle dans la plupart des langages de programmation modernes, en particulier dans les dernières versions de Java, c'est donc un paradigme qu'il devient difficile d'ignorer. Nous utilisons un langage fonctionnel car il offre une syntaxe incitant à utiliser les aspects fonctionnels, et des librairies proposant des interfaces fonctionnelles. Mais tout ce que nous allons apprendre peut aussi se faire dans les langages impératifs ou orientés objets. Il s'agit donc d'enrichir notre catalogue de techniques et d'idées, de façon à plus tard pouvoir choisir la meilleure solution à chaque problème. Et bien souvent, la solution fonctionnelle est la meilleure !