diff --git a/slides/fonctions_dordre_superieur.md b/slides/fonctions_dordre_superieur.md new file mode 100644 index 0000000000000000000000000000000000000000..73918a7cf5aa64190fa5793aa72500f5bfb62587 --- /dev/null +++ b/slides/fonctions_dordre_superieur.md @@ -0,0 +1,216 @@ +--- +title: "Fonctions d'ordre supérieur" +date: "2023-03-21" +--- + +# Tribute + +Rendons à Cesar: + +* Ces slides ont été écrits par Michaël El Kharroubi +* J'arrive pas à changer l'auteur simplement sur un slide donc.... +* Merci à lui pour ses efforts et qu'il soit crédité comme il se doit! + +# Présentation du problème + +* Imaginons que nous ayons la structure d'un vecteur en 3 dimensions suivante + +```C +typedef struct _vec3 { + double x; + double y; + double z; +} vec3; +``` + +* On souhaite implémenter 3 opérations différentes + * La somme + * La soustraction + * Le produit de Hadamard (produit composantes à composantes) + +# Présentation du problème (suite) + +On a donc les fonctions suivantes + +* Addition + +```c +vec3 add(vec3 lhs, vec3 rhs){ + vec3 res; + res.x = lhs.x + rhs.x; + res.y = lhs.y + rhs.y; + res.z = lhs.z + rhs.z; + return res; +} +``` +# Présentation du problème (suite) + + +* Soustraction +```c +vec3 sub(vec3 lhs, vec3 rhs){ + vec3 res; + res.x = lhs.x - rhs.x; + res.y = lhs.y - rhs.y; + res.z = lhs.z - rhs.z; + return res; +} +``` + +# Présentation du problème (suite) + +* Produit de Hadamard + +```c +vec3 mul(vec3 lhs, vec3 rhs){ + vec3 res; + res.x = lhs.x * rhs.x; + res.y = lhs.y * rhs.y; + res.z = lhs.z * rhs.z; + return res; +} +``` + +* Quel est le problème avec ces trois fonctions? + +# Présentation du problème (suite) + +* Le problème avec ces fonctions c'est la **répétition**. +* La seule chose qui change, c'est l'opérateur (+,-,*). +* Problèmes possibles + * Tentation de copier-coller du code (donc risque d'erreurs) + * Faible résilience au changement (imaginons que je veuille des vecteurs 2d, 4d, nd) + +# Présentation du problème (solution) + +* Vecteur de taille dynamique + +```c +typedef struct _vecn { + int size; + double *xs; +} vecn; +``` + +* Règle le problème de résilience du code, mais ne règle pas le problème de répétition... + +# Fonction d'ordre supérieur (solution au problème) + +* Pour notre problème, nous aimerions donc découpler l'opération (opération entre deux termes : +,-,*) de l'itération sur les composantes. + +* Ce qui nous donne conceptuellement en pseudo c + +```c +// Attention pseudo c, ne compile pas !!!!! +vec3 apply_operator(operator op, vec3 lhs, vec3 rhs){ + vec3 res; + res.x = lhs.x op rhs.x; + res.y = lhs.y op rhs.y; + res.z = lhs.z op rhs.z; + return res; +} +``` + +# Fonction d'ordre supérieur (solution au problème) + +* Avec notre fonction conceptuelle `apply_operator`, on pourrait faire (toujours en pseudo c) + +```c +// Attention pseudo c, ne compile pas !!!!! +vec3 add(vec3 lhs, vec3 rhs){ + return apply_operator(+, lhs, rhs); +} +vec3 sub(vec3 lhs, vec3 rhs){ + return apply_operator(-, lhs, rhs); +} +vec3 mul(vec3 lhs, vec3 rhs){ + return apply_operator(*, lhs, rhs); +} +``` + +* En fait, on vient de créer ce qu'on appelle une fonction d'ordre supérieur. + +# Fonction d'ordre supérieur (définition) + +* Une fonction d'ordre supérieur est une fonction qui prend en paramètre et/ou retourne une(des) autre(s) fonction(s). + +* Si on essayait de définir `operator`, c'est en fait une fonction qui prend deux paramètres (un terme de gauche et un terme de droite). On s'en aperçoit clairement avec la notation préfix (polonaise). + * `L + R` -> `+ L R` + * `L - R` -> `- L R` + * `L * R` -> `* L R` + +* Comment l'implémenter concrètement en C? + +# Implémentation + +* Si on reprend la signature de notre fonction d'exemple, on a + +```c +vec3 apply_operator(operator op, vec3 lhs, vec3 rhs); +``` + +* Nous avons déterminé que les `operator` étaient des fonctions qui prennaient deux paramètres. + +* Pour passer une fonction en paramètre en C, nous devons la passer par référence, c'est à dire à l'aide d'un pointeur de fonction. + +# Rappel pointeur de fonctions + +* Un pointeur de fonction se définit ainsi + +```c +typedef + <type retour> (*<nom ptr fonc>)(<type params(s)>); +``` + +* Dans notre cas, nous avons donc un type de fonction nommé `operator`, qui prend en entrée deux `double`{.c} et qui retourne un `double`{.c}. Ce qui nous donne + +```c +typedef double (*operator)(double, double); +``` + +# Implémentation (suite) + +* En reprenant notre fonction `apply_operator`, on a donc + +```c +vec3 apply_operator(operator op, vec3 lhs, vec3 rhs){ + vec3 res; + res.x = op(lhs.x, rhs.x); + res.y = op(lhs.y, rhs.y); + res.z = op(lhs.z, rhs.z); + return res; +} +``` + +* NB : On voit que pour appeler notre fonction passée en paramètre, nous avons pu le faire comme avec n'importe quelle fonction. + +# Résultat + +```c +typedef double (*operator)(double, double); + +vec3 apply_operator(operator op, vec3 lhs, vec3 rhs){ + vec3 res; + res.x = op(lhs.x, rhs.x); + res.y = op(lhs.y, rhs.y); + res.z = op(lhs.z, rhs.z); + return res; +} + +double add_dbl(double lhs, double rhs){return lhs + rhs;} + +vec3 add(vec3 lhs, vec3 rhs){ + return apply_operator(add_dbl, lhs, rhs); +} +``` + +# Fonctions d'ordre supérieur appliquées aux tableaux + +* Comment appliquer des opérations sur un vecteur de taille n? + * Map (application d'une fonction) + * `add_one`, `square` + * Filter (discrimination selon un prédicat) + * `is_even`, `is_lower_than_five` + * Reduce (réduction d'un vecteur à un seul élément) + * `sum`, `multiply` +