Exercices sur le paradigme de programmation fonctionnelle
I. Rappels sur le paradigme fonctionnel⚓︎
Pas d'effets de bord
Avec le paradigme fonctionnel, tous les objets sont immuables et il n'y a pas de variables globales, pas d'effets de bords.
Les affectations
Python permet d'écrire des scripts dans les trois paradigmes : impératif, programmation orientée objet, programmation fonctionelle. Nous allons expérimenter ici la programmation fonctionelle, donc s'interdire les affectation qui peuvent modifier l'état du programme, les utilisations d'objets mutables, les effets de bord.
Dans la plupart des langages fonctionnels il y a une commande qui permet de
donner un nom à une expression avec une syntaxe comme let EXPR be NOM in ... Cela
permet d’éviter que NOM reçoive une autre valeur dans le reste de la fonction, afin d’éviter
les effets de bords. En Python, nous devrons "tricher" et utiliser des affectations en s’assurant qu’une variable ne recevra qu’une seule valeur lors de l’exécution de la fonction.
Les boucles
En programmation fonctionelle, on n'utise pas de boucles forni while. On utilise des fonctions récursives.
Les fonctions sont des données
- Les fonctions peuvent être passées en paramètres d'autres fonctions.
- Les fonctions peuvent renvoyer d'autres fonctions. C'est ce qu'on appelle l'ordre supérieur.
Le paradigme fonctionnel
-
Qu'est-ce qu'un paradigme de programmation ?
- Un langage de programmation spécifique
- Une méthode de débogage du code
- Un style ou une manière d'organiser et d'écrire un programme
- Un algorithme de tri
-
Quelle est la principale caractéristique du paradigme fonctionnel ?
- Les variables peuvent changer de valeur librement
- Le programme est organisé comme une suite d'instructions modifiant l'état du système
- Le programme est organisé comme un enchaînement d'évaluations de fonctions sans effet de bord
- Le programme repose sur l'interaction d'objets
Remarque
.olsL./phngciftîear,d vé;umq050g040d0p0u0g0q0r0q0t0l0j0z0F0m0a0i0k0n0l0R0i0p0b0u0a0r0j0q0i0l0c0F0y0i0G0r0a0j0J0z0O0u0k0a0@0,0.0p0S0h0q0o0X0O0i0n0u0t000w0v0q0b0y0q0U0R0c180P0R0T0V0i1j0x0_110A0y0F0r0w0c0y0b0n1g0/0a0t0y0l170 0u0c0#0U0F190-1l0S1h0~0c170g0r0*0u1K0 0n1x1P0F0b0q1L1H1c160p0s1L0(1j0z1F0l0m0l0p0r0u0b1a1C171G1E0=0q0|0e050f0C. -
Qu'est-ce qu'un effet de bord ?
- Une erreur de syntaxe dans le code
- Une modification de l'état du programme (variable, fichier, affichage…) produite par une fonction
- Le résultat renvoyé par une fonction
- Un paramètre passé à une fonction
Remarque
.8230ols./phngUciè)àftrea,(d véumby050g040k0i0y0t0q0q0t0r0y0x0t0y0D0b0s0x0Q0A0d0m0j0i0S0r0b0B0r0S0C0b0x0m0q0m0l0u0r0m0b0J0R0y0c000A0r0^0Q0B0y0d0E0d0r0n0C0S0L0N0l0r0B0A0S0g0u0s0y0B0%0y0q0{1g0`0J0t0|0t0h0V0d14160m0C0g0c0S0s1x0z0b0m0Q001p0S0z0u1I0B1n0w0.0:0=0t1n1R0y1T0s0m0u0D1I0y0j0c0b0D1U0t0v0y0A0l1+1K0Q0u0i1C1p1r0?0h0m1$1`0u0M261$0y0p0~101}210a0o0e050f0G. -
Qu'est-ce qu'une fonction pure ?
- Une fonction écrite en Python uniquement
- Une fonction qui ne prend aucun paramètre
- Une fonction dont le résultat dépend uniquement de ses paramètres et qui ne produit aucun effet de bord
- Une fonction qui modifie une variable globale
Remarque
.ols.ê/phngUcji-ftread véum050g040k0i0s0v0p0a0i0l0q0n0I0v0g0y0r0F0R0i0w0a0n0F0q0a0y0m0!0r0c0v0b0F0z0e0z0S0x0c0y0b0q0t0q0O0%0*0s0)0-0/0)0t0r0j0y0/0i0q0)0s0`0E0v0z0a0u0n0p0X0v0r0X0i0v0s1o0u0s0h0a0(0v0u000s0b0+0o100s0d050f0B. -
Laquelle de ces propriétés caractérise le paradigme fonctionnel ?
- Les structures de données sont mutables
- Les variables peuvent être réaffectées plusieurs fois
-
Les boucles
whilesont la structure principale - Les structures de données sont immuables
Remarque
.ols:.ê/phngcièftear,d Dvéumbq050h040w0r0j0c0v0b0q0v0h0r0s0r0u0m0k0A0M0o0a0j0l0p0m0Y0j0q0b0t0K0q0J0c0p0s0z0!0z0s0-0v0u0M0u0%0y0_0c0Y0p0v0m0A0A0z0r0B0L0J0d0v0)1b0v0(0N0q0z0x0q0j130O0J0f0:0M0A0a0S0o0m0 0J0r0h0s0n0J0L0@0v0l0s0y0r0#0Y0+0l0M0C0z0m1e0A0h0f0l0i0M1g0q0o0o0q0p0J0{0v0B0a0s0u0e050g0E. -
Qu'est-ce qu'une fonction d'ordre supérieur ?
- Une fonction qui renvoie toujours un entier
- Une fonction qui prend en argument ou renvoie une autre fonction
- Une fonction définie dans une classe
- Une fonction qui ne prend aucun argument
Remarque
.ols»:.ê/pngcjiè)ftear«,(d Dvéumby050i040A0t0j0c0z0b0s0z0i0t0u0t0y0n0k0E0Q0q0a0j0l0r0n0$0j0s0b0w0O0s0N0#0%0)0$0N0c0$0r0z0y0;0z0B0t0P0D0u0N0l0a0E0Z0:0N0t0D0r0u100x0v0z0a0F0m0s0r0N0 0R1h0E0n0o1h0z0l0b0t0c0c0Q0d0p0z0e0z0-0P0N0i0s0D0B0s0j0}0g1g0Q0S1D0C101S0z0T0k0D0Z1T0~000D0,1%1f1y0?0(0*0j1l0D0z1h0j0B0a0G1!17191b12140u0~0Q1h0r0a150f050h0I. -
Parmi les codes Python suivants, lequel respecte le paradigme fonctionnel ?
Remarque
.olsxL:./pngcji)tfear,(d véumb050i04050l0a0w0r040s0m0a0A0p0v0n0u0x0b0o050h0H0J040x0j0r0x0B0I0n0q0n0(0s0A0l0A0%0x0y0s0t0n0s0C0b0(0r0d0n0c0p0s0j0p0(0f0x0l0r0b0s1b0t0z100p0x0t0r0j0y0a0.0x0?0(0j0O0y1d0 0U13180g0x0e0r0c0x0:0p1m1H0a0i0p0n0a0j1H0i0t0I0A131n1k0p0O181H0J1H0r0q0q0r0p1(0(0C0a0t0w0x0v0*0w0,0n0l0s1P1R0x0w001t0^0`0|0~100d180t0@0O230(1e1A140(0i0s0c0c1i0x1n1I0t0k0A0B1Z0o0g0X0E. -
À quoi sert le mot-clé
lambdaen Python ?- À importer un module
- À définir une classe anonyme
- À définir une fonction anonyme (sans nom)
- À créer une boucle infinie
Remarque
.olsxL.:/pPn2c*i)-tfear(d éumby050i040e0t0y0B0a0r0q0m0b0z0y050m0a0x0t040b0u0B0C0x0u050h0T0V040y0i0t0v0B0t0r0y0V0y0m0v0z0/0@0t0c0y0s0a0k0m0r0o13100u0k130D0;100w0c1a100S0U0W0V0s0(0*0W0p0y0c0a0A10120:0I0T0k0V0k0c0|0f0y0j0u0v0y0t0d0t0B0i0b0I0g0R1q0X0Z0#0u0y0d1U0d0n0n0l1p1l040f0(0F. -
Pourquoi le paradigme fonctionnel facilite-t-il les tests et le débogage ?
- Parce que les fonctions sont toujours courtes
- Parce qu'il n'y a pas d'effets de bord : chaque fonction peut être testée indépendamment avec les mêmes résultats pour les mêmes entrées
- Parce que Python affiche automatiquement les erreurs
- Parce que le code fonctionnel ne peut pas contenir de bugs
Remarque
.çolsL.ê/pngcjiftear,d éumbq050i040e000r0z0d0q0j0l0q0v0u000q0o0o0q0p0d0N0M0z0b0s0u0v0T0v0c0r0v0p0s0r0j0d0i0r0s0J0L0v0s0w0o0w0?0j0p0n0q0c0c0M0k0=0.100d0I0 0v0A0x000x0j0M0o0b0K101l0v0i0x0?0v0I0v0l0b0y0i0Z0p0M0p0b0x0m1E0s0V0u0M0)0v0y0g0y1j0r0a1o1z1r0W0V0J0,0w0q0V0n1K0 0n1e1$0t1v0M1e0n1t0n1y0c0n0o110v0k0-0j1K1Q1c140V1B0d0U0v1h0n0p0r0n0?0d0f050h0C. -
Laquelle de ces affirmations sur Python est vraie ?
- Python est un langage exclusivement fonctionnel
- Python est un langage exclusivement impératif
- Python est un langage multi-paradigmes permettant d'écrire du code impératif, fonctionnel et orienté objet
- Python interdit les effets de bord
Remarque
.ols:./phPngcji)-tfear,(d véumby050g040i0E0q0h0a0j0y0s0c0q0y0B0N0b0t0j0k0t0k0s0y0k0A0j0A0u0t0b0n0Q0#0w0C0B0b0q0n0p0g0t0+0x0n0k0C0P0o0y0d0y0n0b0y0g0s0u110R0x000A0l0u0n0u0#0x0P190u0a0k0+0C110c0y0x0W1w0b0#0Q0E1B160C0g0*0t0^0r0v0y0r0M0l0^0M0j0s180a0B0y0a1j0s0j0q0A1Z0D0m0s0q1N0c1V0M0y1B1w0D0P0a0n0j1w0x1Y0x0A0z1;0g1a0B0u0e050f0G.
II. Exercices sur la structure abstraite de Liste⚓︎
Implémentation des listes utilisée dans tous les exercices
Un exemple d'interface fonctionnelle pour le type abstrait Liste
La valeur d'une liste est un tuple de tuple ce qui est une structure immuable en Python.
Exécuter le code ci-dessous. Il sera toujours présent (caché) dans les exercices de ce paragraphe.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exemple d'utilisation
Ce sera la seule affectation de tous les exercices de cette page. Voir le paragraphe ci-dessus.
Cliquer sur le + pour lire le commentaire
Pas d'effet de bord
L'exemple précédent montre qu'on n'a pas d'effet de bord.
Contrainte
👉 Dans tous les exercices, il faudra utiliser des fonctions données ci-dessus dans l'implémentation de la structure abstraite liste.
Exercice 0 :⚓︎
Créer une liste
Ecrire l'instruction qui permet de créer la liste : (4, (3, (2, (1, ())))) sans utiliser aucune affectation.
Faire l'affichage de la liste pour vérifier.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Solution
Exercice 1 :⚓︎
Longueur d'une liste
Compléter la fonction récursive longueur qui prend en paramètre une liste implémentée comme ci-dessus liste,
et renvoie la longueur de cette liste.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exercice 2 :⚓︎
Minimum d'une liste
Compléter la fonction récursive minimum qui prend en paramètre une liste non vide implémentée comme ci-dessus liste,
et renvoie le plus petit élément de cette liste.
👉 il faudra utiliser la fonction min de python
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exercice 3 :⚓︎
Une liste contient-elle un élément ?
Compléter la fonction récursive contient qui prend en paramètre une liste implémentée comme ci-dessus liste, et un élément v.
Cette fonction doit renvoyer un booléen indiquant si v est dans liste.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exercice 4 :⚓︎
Fonction d'ordre supérieur
Compléter applique(f, liste) qui renvoie une nouvelle liste correspondant aux images des éléments de liste par la fonction f.
Exemple :
>>> applique(lambda x: x*x, cons(4, cons(13, cons(1, cons(5, creer_liste())))))
(16, (169, (1, (25, ()))))
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
III. Exercices sur la structure abstraite d'arbre binaire⚓︎
On représentera dans tous les exercices qui suivent les arbres binaires ainsi :
- l'arbre vide est représenté par
None, - un arbre non vide est représenté par un tuple
(sous-arbre gauche, valeur, sous-arbre droit).
Ainsi le tuple ((None, 6, None), 15, None) représente l'arbre suivant :
graph TD
R(15) --> A(6)
R -.-x B( )
A -.-x C( )
A -.-x D( )
style B display:none;
style C display:none;
style D display:none;
Exercice 5 :⚓︎
Fonctions de base à réutiliser dans les autres exercices
Compléter les fonctions est_vide, gauche, droite, racine qui prennent en paramètre un arbre binaire
implémenté comme ci-dessus, et renvoient respectivement un booléen indiquant si l'arbre est vide,
le sous arbre gauche, le sous arbre droit, la racine de arbre.
Ces fonctions seront ensuite dans du code caché pour les questions suivantes.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exercice 6 :⚓︎
Taille d'un arbre binaire
Compléter la fonction récursive taille qui prend en paramètre arbre, un arbre binaire implémenté comme ci-dessus,
et renvoie sa taille.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exercice 7 :⚓︎
Hauteur d'un arbre binaire
On convient que la hauteur d'un arbre ne contenant qu'un élément est 1.
Compléter la fonction récursive hauteur qui prend en paramètre arbre, un arbre binaire implémenté comme ci-dessus,
et renvoie sa hauteur.
👉 il faudra utiliser la fonction max de python
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exercice 8 :⚓︎
Un arbre contient-il un élément ?
Compléter la fonction récursive appartient qui prend en paramètres arbre, un arbre binaire implémenté comme
ci-dessus, et un élément valeur. Cette fonction doit renvoyer un booléen indiquant si l'élément valeur est dans l'arbre.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Exercice 9:⚓︎
Maximum d'une arbre
Compléter la fonction récursive maximum qui prend en paramètre un arbre binaire non vide implémentée comme ci-dessus arbre,
et renvoie le plus grand élément de cet arbre.
👉 il faudra utiliser la fonction max de python. Vous pourrez utiliser la fonction taille vue plus haut.
# Tests (insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)
Crédits⚓︎
Frédéric Junier, Romain Janvier
Remarque
.ols./pngUciètfrea,d véumy050f040i0g0t0f0q0o0q0s0k0h0x0p0t0s0N0f0o0a0h0H0x0x0q0m0k0a0D0s0v0n0k0g0k0m0t0w0D0c0m0y0b0N0P0E0S0U0q0W0Y0!0g0r0.0g0N0X0+0l0o0^0N0j0#0j0p0u0a0k0o0t0p0-0s000a0o0h0q0+0c0p1j0@0t1c0P0d050e0A.