26 août 2016

Paradigme de programmation fonctionnel

Design & Code

Philippe

Boulanger

Image ordinateur.

26 août 2016

Paradigme de programmation fonctionnel

Design & Code

Philippe

Boulanger

Image ordinateur.

26 août 2016

Paradigme de programmation fonctionnel

Design & Code

Philippe

Boulanger

Image ordinateur.

Cet article sur le paradigme de programmation fonctionnel est le 3ème de notre série sur les paradigmes de programmation. N'hésitez pas à prendre connaissance des deux premiers articles :

Lambda-calcul, un système du paradigme de programmation fonctionnel

Créée par Alonzo Church en 1930, cette théorie mathématique

définit les fondations des fonctions et des applications. C’est le premier

formalisme qui permet de gérer les fonctions récursives. Le lambda-calcul, la

machine de Turing et le modèle Herbrand-Gödel sont des éléments essentiels de

la théorie de la calculabilité.


L’un des principes du lambda-calcul est que « tout est fonction ». Comme le changement d'état et la mutation des données ne peuvent pas être représentés par des évaluations de fonctions la programmation fonctionnelle ne les admet pas, au contraire elle met en avant l'application des fonctions, contrairement au modèle de programmation impérative qui met en avant les changements d'état.

Lisp

En 1958, John Mac Carthy et son équipe implémente le premier interpréteur LISP (LISt Processing ou, pour les médisants, Lots of Idiot and Stupid Parenthesis) en se basant sur la

théorie du lambda-calcul. Dédié à résoudre des problèmes qui ne pouvait pas

être résolu par FORTRAN (notamment grâce à la récursivité), le Lisp est à

l’origine de beaucoup de progrès en informatique théorique. La programmation

orientée objet dérive des langages fonctionnels : Smalltalk le premier

langage objet qui a été popularisé était écrit en Lisp…


Le Lisp est un langage dit préfixé : la fonctionnelle

est toujours en première position ce qui facilite le parsing. Le noyau de base

est composé de très peu d’instructions (defun, car, cdr, cond, cons et les

opérateurs de base). C’est, donc, un langage relativement simple mais très

expressif :


  • ( + 5 3)
    -> 8

  •  (/ 8 2)
    -> 4

  • (defun f(x) (* x x))
    -> définit une fonction f qui prend un argument x et qui retourne x*x

De nombreuses variantes de Lisp ont été développé au cours

du temps. La plus répandue aujourd’hui est GNU Common Lisp. Lisp est aussi le

langage de macros dans emacs (un éditeur de texte sous unix qui est très populaire),

ou sous sa version AutoLisp le langage de macros dans AutoCAD.

Pour en apprendre plus, je vous conseille de jeter à œil à : https://fr.wikipedia.org/wiki/Lisp.


Concepts sous-jacent du paradigme fonctionnel

La pureté

Les fonctions sont dites 'pure' lorsqu'elles ont des résultats qui ne dépendent strictement que de leurs arguments, sans autre effet externe. Voici un exemple de fonction pure :

def f( i ):
	return i + 4
>> f(1)
5
>> f(1)
5

Voici un exemple de fonction impure :

n = 4
def f( i ):
	global n
	n += i
	return n
>> f(1)
5
>> f(1)
6

Une fonction pure permet de cloisonner, de localiser le code

mis en œuvre. Cela augmente sa stabilité, son déterminisme et facilite sa

compositionnalité.


Fonction de première classe

Être de première classe, c’est donc avoir le même statut qu’une valeur telle qu’un entier ou un caractère, c’est-à-dire :

  • Pouvoir être nommé, affecté (et typé) :

x=sin

  • Pouvoir être défini et créé à la demande :

x= lambda x: x+1

  • Pouvoir être passé en argument à une fonction :

map(lambda x: x*x, [1, 3, 4 ] )

  • Pouvoir être le résultat d’une fonction :

(f( 3 ) ) ( 5 )

  • Pouvoir être stocké dans une structure de données quelconque :

array=[ log, exp, tan ]

Notion de fermeture

Mais, pour être pure et/ou de première classe, une fonction doit parfois être transformée en fermeture (closure), i.e. l’association du code de la fonction avec un environnement de définitions.


La fonction f retourne une fonction h qui prend un argument mais dépend des 2 arguments passés à f.

Exemple de paradigme fonctionnel

Voici un exemple de fonction qui parcourt récursivement une arborescence de fichiers et, qui pour chaque fichier qui respecterait un ‘prédicat’ appliquerait une fonction.


Sans programmation fonctionnelle, ce type d’implémentations serait impossible.

Conclusion

  • La programmation fonctionnelle est bonne pour le

    développement de programmes : pureté et première classe induisent une part de stabilité,

    déterminisme, testabilité, cloisonnement, fluidité d’utilisation,

    compositionalité, généralisation, extensibilité, etc.

  • La programmation fonctionnelle est bonne pour

    l’objet-modulaire : elle met un peu d’huile dans les rouages, et amoindrit parfois

    la complexité des architectures.

  • La programmation fonctionnelle est soluble :

    pureté et première classe des fonctions peuvent être considérées, incluses et

    facilitées dans n’importe quel langage.

La plupart des langages supportent le paradigme fonctionnel : Python, C++, Java, C#, etc…