252 lines
7.8 KiB
Markdown
252 lines
7.8 KiB
Markdown
## Paradigmes de programmation
|
||
|
||
> Un paradigme est à la programmation ce qu’un style culinaire est à la cuisine : il impose des règles, des outils, et une manière de faire.
|
||
|
||
|
||
|
||

|
||
|
||
------
|
||
|
||
### Introduction
|
||
|
||
En programmation, il n’existe pas qu’une seule bonne façon de penser. Comme pour résoudre un problème de maths ou construire une maison, plusieurs approches sont possibles. Ces manières de faire s’appellent des ***paradigmes***.
|
||
|
||
On appelle paradigme une méthode de programmation.
|
||
|
||
On peut regrouper les différents paradigmes en 2 catégories :
|
||
|
||
- la programmation **impérative** ;
|
||
- la programmation **déclarative**.
|
||
|
||
Lorsque l'on utilise la programmation impérative, on décrit le comment / la solution. On la retrouve dans plusieurs langage :
|
||
|
||
- Structurée (FORTRAN, C)
|
||
- Procédurale (FORTRAN, C)
|
||
- Objet (C++, Java, Python)
|
||
- Modulaire (C++, Java, Python)
|
||
|
||
Lorsque l'on utilise la programmation déclarative, on décrit le quoi / le problème. On la retrouve dans plusieurs langage :
|
||
|
||
- Descriptif (HTML, SQL)
|
||
- Fonctionnel (LISP, CAML)
|
||
- Logique (Prolog, SQL)
|
||
|
||
-------
|
||
|
||
### Programmation fonctionnelle
|
||
|
||
#### Les différences
|
||
|
||
La programmation impérative, bien que versatile, conduit rapidement à des programmes difficiles à comprendre et à maintenir, où la démonstration de la correction est impossible.
|
||
|
||
Ceci est du au fait qu’un traitement de données :
|
||
|
||
- dépend de paramètres extérieurs non maîtrisés : variables ;
|
||
- modifie les données, ou d’autres : affectation ;
|
||
- réalise une tâche complexe : une fonction complexe.
|
||
|
||
```
|
||
a = 3
|
||
|
||
répéter 5 fois :
|
||
a = a + 2
|
||
|
||
afficher a
|
||
```
|
||
|
||
|
||
|
||
La programmation fonctionnelle pure s’absout de ces problèmes :
|
||
|
||
- pas de variables
|
||
- pas d’affectation
|
||
- enchaînement de fonctions simples.
|
||
|
||
```
|
||
f : x -> x + 2
|
||
|
||
afficher f(f(f(f(f(3)))))
|
||
```
|
||
|
||
|
||
|
||
#### Le principe
|
||
|
||
Le but d'un traitement informatique est de produire des données à partir de données.
|
||
|
||
Le programme est une une fonction qui associe des données sortantes à des données entrantes.
|
||
|
||
```
|
||
f : données entrantes -> données sortantes
|
||
Pas d'état interne
|
||
Les données sont non mutables
|
||
```
|
||
|
||
Un traitement complexe s'obtiendra en composant plusieurs fonctions intermédiaires simples et une boucle s’obtiendra par une fonction qui s’appelle elle-même : **récursivité**.
|
||
|
||
En clair : **__La variable n'existe pas !__**.
|
||
|
||
#### Avantages et les inconvénients
|
||
|
||
Pour les avantages :
|
||
|
||
- Absence d’effets de bord.
|
||
- Toute fonction fournit un résultat prédictible qui est toujours le même.
|
||
- Clarifie l’interprétation du programme et facilite sa correction.
|
||
- Évite l’apparition de bugs non prédictibles.
|
||
|
||
En revanche, on retrouve des inconvénients :
|
||
|
||
- Un traitement classique nécessite un grand nombre de fonctions.
|
||
- Nuit au développement de grosses applications.
|
||
- Gourmand en ressources (stockage des résultats intermédiaires, pile des appels récursifs).
|
||
- Certaines fonctions doivent pouvoir modifier des données extérieures, ou en dépendre.
|
||
|
||
#### Effets de bord
|
||
|
||
Une fonction à effet de bord est une fonction qui modifie ou utilise une variable extérieure à son environnement local (variables globales, opérations d’entrées/sorties).
|
||
|
||
**__À n’utiliser que lorsque cela est nécessaire !__**
|
||
|
||
Les effets de bord peuvent être évité facilement grâce au principe de localité des variables et la programmation fonctionnelle.
|
||
|
||
```python
|
||
# Fonction avec effets de bord :
|
||
|
||
def ajoute_k_a_n(k):
|
||
global n
|
||
n = n + k
|
||
return n
|
||
|
||
n = 2
|
||
print("Avec k=2 : ", ajoute_k_a_n(2))
|
||
print("Avec k=3 : ", ajoute_k_a_n(3))
|
||
```
|
||
|
||
```python
|
||
# Fonction sans effets de bord :
|
||
|
||
def ajoute_k_a_n(n, k):
|
||
return n + k
|
||
|
||
print("Avec k=2 : ", ajoute_k_a_n(2))
|
||
print("Avec k=3 : ", ajoute_k_a_n(3))
|
||
```
|
||
|
||
#### Fonctions lambdas
|
||
|
||
λ-calcul (années 1930) : un système formel inventé par Alonzo Church qui fonde les concepts de fonction et d'application. Il s'agit du premier formalisme qui définit et caractérise les fonctions récursives.
|
||
|
||
```lambda : x -> expression(x)```
|
||
|
||
Tout comme la machine de Turing, le λ-calcul peut représenter n’importe quel calcul (hypothèse de Church-Turing, chaque approche peut être exprimée dans l’autre).
|
||
|
||
La programmation **fonctionnelle** puise son origine du __λ-calcul__ alors que la programmation **impérative** puise son origine de la __machine de Turing__.
|
||
|
||
En python la lambda fonction se définie à l'aide du mot clé **lambda** :
|
||
|
||
```python
|
||
add_a_b = lambda a,b: a + b
|
||
|
||
entre_10_et_20 = lambda x : True if (x > 10 and x < 20) else False
|
||
```
|
||
|
||
Appelée aussi fonction anonyme, il ne faut pas en abuser en Python, elle :
|
||
|
||
- est utile pour définir une fonction simple, proche d’une définition mathématique, en une ligne ;
|
||
- est utile pour créer la fonction de sortie d’une fonction d’ordre supérieur ;
|
||
- est utile pour composer les fonctions ;
|
||
- peut utiliser les mots clés if et else ;
|
||
- peut s’utiliser avec les fonctions d’ordres supérieur (exemple du tri de Python) ;
|
||
- peut s’utiliser conjointement à la compréhension de listes.
|
||
|
||
#### Fonctions et listes
|
||
|
||
__Le mapping__
|
||
|
||
Appliquer une fonction à chaque élément d'une liste.
|
||
|
||
```python
|
||
f = lambda x: x*5
|
||
liste = [2, 7, -1]
|
||
resultat = map(f, liste)
|
||
```
|
||
|
||
__La réduction__
|
||
|
||
Combiner les éléments d’une liste en appliquant une fonction à l’aide d’un accumulateur (à l’état initial, acc prend la première valeur de la liste et x la deuxième, le résultat est stocké dans acc).
|
||
|
||
```python
|
||
liste = [1, 3, 5, 6, 2]
|
||
f_somme = lambda acc, x: acc + x
|
||
somme = functools.reduce(f_somme, liste)
|
||
```
|
||
|
||
```python
|
||
liste = [1, 3, 5, 6, 2]
|
||
f_maximum = lambda acc, x: acc if acc > x else x
|
||
maximum = functools.reduce(f_maximum, liste)
|
||
```
|
||
|
||
__Le filtrage__
|
||
|
||
Sélection les éléments d’une liste vérifiant un certain critère.
|
||
|
||
```python
|
||
liste = [1, 3, 5, 6, 2]
|
||
f_filtre = lambda x: x >= 3
|
||
liste_filtree = filter(f_filtre, liste)
|
||
```
|
||
|
||
#### Boucler en programmation fonctionnelle
|
||
|
||
On utilise la récursivité, la fonction s’appelant elle-même un certain nombre de fois.
|
||
|
||
```python
|
||
def ajoute_5(n, x):
|
||
if n == 0:
|
||
return x
|
||
else:
|
||
return ajoute_5(n - 1, x + 5)
|
||
|
||
resultat = ajoute_5(3, 2)
|
||
print(resultat)
|
||
```
|
||
|
||
On peut aussi plus simplement appliquer une réduction sur une liste de *n* éléments.
|
||
|
||
```python
|
||
ajoute_5 = lambda acc, x: acc + 5
|
||
resultat = functools.reduce(ajoute_5, range(3), 2) # avec 2 pour valeur initiale de l'accumulateur
|
||
print(resultat)
|
||
```
|
||
|
||
----------------
|
||
|
||
#### Exemples de langages multi-paradigmes
|
||
|
||
- Python : impératif, objet, fonctionnel
|
||
- JavaScript : impératif, objet, fonctionnel
|
||
- Scala : objet + fonctionnel
|
||
- Rust : impératif + fonctionnel
|
||
|
||
----------
|
||
|
||
### Exercice
|
||
|
||
Voici une tâche simple : nous voulons faire cuire des pâtes.
|
||
|
||
Écrire la recette sous forme de code python :
|
||
|
||
- **Version impérative : liste d’instructions étape par étape.**
|
||
- **Version fonctionnelle : une fonction pure qui prend un état (pâtes non cuites) et retourne un nouvel état (pâtes cuites).**
|
||
- **Version orientée objet : créer une classe** Pates *avec une méthode* cuire().
|
||
|
||
------
|
||
|
||
Auteurs : Florian Mathieu, Timothée Decoster, Enzo Frémaux
|
||
|
||
Licence CC BY NC
|
||
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>. |