Approches Fonctionnelles de la Programmation - 48 - LRDE

publicité
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Approches Fonctionnelles de la Programmation
e Introduction E
Didier Verna
EPITA / LRDE
[email protected]
lrde/̃didier
@didierverna
didier.verna
google+
in/didierverna
Plan
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Un paradigme de Programmation
La Fonction : un Objet de 1re Classe
Programmation Fonctionnelle (Im)Pure
Évaluation Stricte / Paresseuse
Résumé
AFP / Introduction – Didier Verna
2/24
Plan
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Un paradigme de Programmation
La Fonction : un Objet de 1re Classe
Programmation Fonctionnelle (Im)Pure
Évaluation Stricte / Paresseuse
Résumé
AFP / Introduction – Didier Verna
3/24
Paradigme
1er Ordre
Pureté
Un Paradigme de Programmation
Évaluation
Résumé
« Quoi faire » plutôt que « Comment faire »
I Un paradigme ?
I
I
I
I
Affecte l’expressivité d’un langage
Affecte la manière de penser dans un langage
Le concept de paradigme est poreux
Lequel ?
I
I
I
Expressions
Définitions (expressions nommées)
Évaluations (de définitions ou d’expressions)
AFP / Introduction – Didier Verna
4/24
Paradigme
1er Ordre
De l’Impératif au Fonctionnel
Pureté
Évaluation
Résumé
« La somme des carrés des entiers entre 1 et N »
C (impératif)
Lisp
int ssq (int n)
{
int i = 1, a = 0;
while (i <= n)
{
a += i*i;
i += 1;
}
return a;
}
(defun ssq (n)
(if (= n 1)
1
(+ (* n n) (ssq (1- n)))))
Haskell
ssq :: Int -> Int
ssq 1 = 1
ssq n = n*n + ssq (n-1)
C (récursif)
int ssq (int n)
{
if (n == 1)
return 1;
else
return n*n + ssq (n-1);
}
AFP / Introduction – Didier Verna
I
Clarté
I
Concision
5/24
Paradigme
De l’Impératif à l’Envers
1er Ordre
Pureté
Évaluation
Résumé
« La racine carrée de la somme des carrés de a et de b »
C (impératif)
Haskell
float hypo (float a, float b)
{
float a2 = a*a;
float b2 = b*b;
float s = a2 + b2;
hypo :: Float -> Float -> Float
hypo a b = sqrt ((a*a) + (b*b))
}
return sqrt (s);
Lisp
(defun hypo (a b)
(sqrt (+ (* a a) (* b b))))
C (moins impératif)
Pour être tout à fait honnête :
float hypo (float a, float b)
{
return sqrt (a*a + b*b);
}
Haskell (100% préfixe)
AFP / Introduction – Didier Verna
hypo :: Float -> Float -> Float
hypo a b = sqrt ((+) ((*) a a) ((*) b b))
6/24
Plan
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Un paradigme de Programmation
La Fonction : un Objet de 1re Classe
Programmation Fonctionnelle (Im)Pure
Évaluation Stricte / Paresseuse
Résumé
AFP / Introduction – Didier Verna
7/24
Paradigme
La Fonction : un Objet de
1er Ordre
1re
Pureté
Classe
Évaluation
Résumé
1er ordre, ordre supérieur etc.
I Christopher Strachey (1916-1975)
I
I
I
I
I
I
I
I
nommage (variables)
agrégation (structures)
argument de fonction
retour de fonction
manipulation anonyme
construction dynamique
…
Plus d’expressivité (clarté, concision etc.)
AFP / Introduction – Didier Verna
8/24
Paradigme
1er Ordre
Pureté
Nommage, Affectation, Agrégation
Évaluation
Résumé
Aussi simple que d’écrire i = j
Haskell
backwards :: [a] -> [a]
backwards = reverse
Scheme
(define backwards reverse)
Lisp
(setf (symbol-function 'backwards) #'reverse)
AFP / Introduction – Didier Verna
9/24
Paradigme
Arguments Fonctionnels
1er Ordre
Pureté
Évaluation
Résumé
Deux archétypes : mapping et folding
I
I
mapping : traiter individuellement les éléments d’une liste par une
fonction
Lisp
Haskell
(mapcar #'sqrt '(1 2 3 4 5))
map sqrt [1..5]
folding : combiner les éléments d’une liste par une fonction
Lisp
Haskell
(reduce #'+ '(1 2 3 4 5))
foldr1 (+) [1..5]
sum [1..5]
AFP / Introduction – Didier Verna
10/24
Fonctions Anonymes
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Des littéraux comme les autres
I
I
Possibilité de ne pas nommer les fonctions
Lisp
Haskell
(lambda (x) (* 2 x))
\x -> 2 * x
Utilisation littérale (comme tout autre type de donnée)
Lisp
Haskell
((lambda (x) (* 2 x)) 4)
(\x -> 2 * x) 4
AFP / Introduction – Didier Verna
11/24
Paradigme
1er Ordre
Pureté
Retours Fonctionnels (Anonymes)
Évaluation
Résumé
Aussi simple que return 42;
Lisp
(defun adder (n)
(lambda (x) (+ x n)))
Haskell
adder :: Int -> (Int -> Int)
adder n = \x -> x + n
AFP / Introduction – Didier Verna
12/24
Pseudo-1er
Paradigme
1er Ordre
Ordre en Impératif
Pureté
Évaluation
Résumé
On fait ce qu’on peut…
I
Les structures de contrôle impératives sont des formes fixes de
fonctions d’ordre supérieur
if (expression)
{ /* ANONYMOUS PROCEDURE ! */
/* blah blah ... */
}
else
{ /* ANONYMOUS PROCEDURE ! */
/* blah blah ... */
}
AFP / Introduction – Didier Verna
13/24
Plan
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Un paradigme de Programmation
La Fonction : un Objet de 1re Classe
Programmation Fonctionnelle (Im)Pure
Évaluation Stricte / Paresseuse
Résumé
AFP / Introduction – Didier Verna
14/24
Paradigme
1er Ordre
Pureté
Programmation Fonctionnelle Pure
Évaluation
Résumé
La fonction au sens mathématique
(
1
si x = 1,
ssq(x) =
x 2 + ssq(x − 1) sinon.
I
ssq :: Int -> Int
ssq 1 = 1
ssq n = n*n + ssq (n-1)
Fonction
I
I
I
Haskell
Impératif : (procédure) ensemble de calculs à effets de bords avec
éventuellement retour d’une valeur
Fonctionnel Pur : calcul d’une valeur de sortie (retour) en fonction
de valeurs d’entrée (arguments)
Variable
I
I
Impératif : stockage d’information qui varie au cours du temps
(mutation)
Fonctionnel Pur : (constante) valeur inconnue ou arbitraire
AFP / Introduction – Didier Verna
15/24
Intérêts de la Pureté
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Pureté =⇒ (plus de) sureté
I Parallélisme
I
I
Sémantique locale aux fonctions
I
I
Cf. Erlang
Tests locaux / Bugs locaux
Preuve de programme
AFP / Introduction – Didier Verna
16/24
Preuves Formelles
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Induction mathématique
« Prouvez-moi (s’il vous plaît) que ∀N, ssq(N) > 0 »
Fonctionnel pur
Impératif
Haskell
C
ssq :: Int -> Int
ssq 1 = 1
ssq n = n*n + ssq (n-1)
int ssq (int n)
{
int i = 1, a = 0;
while (i <= n)
{
a += i*i;
i += 1;
}
return a;
}
I
I
C’est vrai au rang 1
Supposons que ce soit vrai
au rang N − 1…
I
AFP / Introduction – Didier Verna
Euh…
17/24
Paradigme
1er Ordre
Pureté
Évaluation
Limites du Formalisme Mathématique
Résumé
Comment exprimer le concept de « racine carrée » ?
sqrt(x) = y|
(
Lisp
y >0
y2 = x
Lisp
(defun sqrtp (s x)
(and (> s 0)
(= (* s s) x)))
(defun sqrt (x) ???)
Haskell
Haskell
sqrtp :: Float -> Float -> Bool
sqrtp s x = s > 0 && s*s == x
sqrt :: Float -> Float
sqrt x = ???
I
Au final, il faut bien expliquer comment faire…
I
Mais on repousse le problème : déclaratif ou impératif ?
AFP / Introduction – Didier Verna
18/24
Plan
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Un paradigme de Programmation
La Fonction : un Objet de 1re Classe
Programmation Fonctionnelle (Im)Pure
Évaluation Stricte / Paresseuse
Résumé
AFP / Introduction – Didier Verna
19/24
Paradigme
1er Ordre
Pureté
Évaluation Stricte / Paresseuse
Évaluation
Résumé
À quel moment calculer la valeur d’une expression ?
I
I
Stricte : Lisp
Les arguments (expressions) sont évalués d’abord
Paresseuse (lazy) : Haskell
Les expressions ne sont évaluées que quand le besoin s’en fait sentir
(idem pour les agrégats)
AFP / Introduction – Didier Verna
20/24
Paradigme
1er Ordre
Pureté
Évaluation Stricte / Paresseuse
Évaluation
Résumé
La paresse : une vertu ?
I
I
Intérêt : plus d’abstraction
(ex. manipulation de listes infinies)
Lisp
Haskell
(defun intlist (s)
(cons s (intlist (1+ s))))
intlist :: Int -> [ Int ]
intlist s = s : intlist (s + 1)
;; KO
-- OK
Contrainte : pureté fonctionnelle requise
(on ne peut pas s’appuyer sur l’ordre d’évaluation)
AFP / Introduction – Didier Verna
21/24
Paradigme
1er Ordre
Pseudo-Paresse en Impératif
Pureté
Évaluation
Résumé
On ne fait toujours que ce qu’on peut…
I
Les structures de contrôle impératives sont des formes
embryonnaires d’évaluation paresseuse.
if (1)
{ /* COMPUTED */
/* blah blah ... */
}
else
{ /* NOT COMPUTED ! */
/* blah blah ... */
}
AFP / Introduction – Didier Verna
22/24
Plan
Paradigme
1er Ordre
Pureté
Évaluation
Résumé
Un paradigme de Programmation
La Fonction : un Objet de 1re Classe
Programmation Fonctionnelle (Im)Pure
Évaluation Stricte / Paresseuse
Résumé
AFP / Introduction – Didier Verna
23/24
Paradigme
1er Ordre
Pureté
Évaluation
Bénéfices de l’Approche Fonctionnelle
Résumé
Les 3 caractéristiques des (bons) langages
Primitives
Procédures / Données
Combinaisons
Abstractions
I
Moins de distinction entre procédures et données
I
Plus de puissance dans la combinaison
I
Plus de puissance dans l’abstraction
AFP / Introduction – Didier Verna
24/24
Téléchargement