Skip to content

4. Fonctions d'Ordre Supérieur

Les Fonctions sont des Valeurs

En Gleam, une fonction est une valeur comme une autre. On peut la stocker dans une variable, la passer en paramètre, la retourner.

// Un entier
let x: Int = 42

// Une fonction - même statut que x
let double: fn(Int) -> Int = fn(n) { n * 2 }

// On peut passer une fonction en paramètre
pub fn appliquer(f: fn(Int) -> Int, valeur: Int) -> Int {
  f(valeur)
}

appliquer(double, 5)   // -> 10

Fonctions Anonymes (Lambdas)

Une fonction anonyme est une fonction sans nom, définie sur place avec fn.

// Fonction nommée
pub fn double(x: Int) -> Int { x * 2 }

// Fonction anonyme équivalente
fn(x) { x * 2 }

Exemples

fn(x) { x + 1 }                  // ajoute 1

fn(x) { x * x }                  // carré

fn(x) { x > 0 }                  // teste si positif

fn(x, y) { x + y }               // addition (2 paramètres)

Pourquoi utiliser des lambdas ?

Cas typique : fonction utilisée une seule fois

// Définir une fonction nommée juste pour ça : verbeux
pub fn double(x: Int) -> Int { x * 2 }
let resultat = appliquer(double, 5)

// Lambda : plus direct
let resultat = appliquer(fn(x) { x * 2 }, 5)

Fonctions d'Ordre Supérieur

Une fonction d'ordre supérieur prend une ou plusieurs fonctions en paramètres.

map : Transformer Chaque Élément

D'abord, écrivons-la à la main :

pub fn map(f: fn(a) -> b, lst: Liste(a)) -> Liste(b) {
  case lst {
    Vide -> Vide
    Cons(tete, queue) -> Cons(f(tete), map(f, queue))
    //                        ↑
    //                        on transforme la tête
  }
}

Utilisation :

map(fn(x) { x * 2 }, Cons(1, Cons(2, Cons(3, Vide))))
// -> [2, 4, 6]

map(fn(x) { x > 5 }, Cons(3, Cons(7, Cons(2, Vide))))
// -> [False, True, False]

Visualisation :

[1,    2,    3   ]
 ↓     ↓     ↓
[1*2,  2*2,  3*2 ]
= [2,  4,    6   ]

Avec le pipe :

lst
|> map(fn(x) { x * 2 })    // double chaque élément
|> somme                    // additionne


filter : Garder Certains Éléments

D'abord, à la main :

pub fn filter(pred: fn(a) -> Bool, lst: Liste(a)) -> Liste(a) {
  case lst {
    Vide -> Vide
    Cons(tete, queue) ->
      case pred(tete) {
        True  -> Cons(tete, filter(pred, queue))  // on garde
        False -> filter(pred, queue)              // on jette
      }
  }
}

Utilisation :

filter(fn(x) { x > 5 }, Cons(3, Cons(7, Cons(2, Cons(9, Vide)))))
// -> [7, 9]

filter(fn(x) { x % 2 == 0 }, Cons(1, Cons(2, Cons(3, Cons(4, Vide)))))
// -> [2, 4]

Trace d'exécution :

filter (x > 5) [3, 7, 2, 9]
= 3 > 5 ? Non  → on jette, filter [7, 2, 9]
= 7 > 5 ? Oui  → Cons(7, filter [2, 9])
= 2 > 5 ? Non  → on jette, filter [9]
= 9 > 5 ? Oui  → Cons(9, filter [])
= []
= [7, 9]

Avec le pipe :

lst
|> filter(fn(x) { x % 2 == 0 })  // garde les pairs
|> map(fn(x) { x * x })          // met au carré
|> somme                          // additionne


map et filter Combinés

Ces deux fonctions se composent naturellement via le pipe :

// Somme des carrés des nombres pairs
pub fn sommeCarresPairs(lst: Liste(Int)) -> Int {
  lst
  |> filter(fn(x) { x % 2 == 0 })  // [2, 4, 6]
  |> map(fn(x) { x * x })          // [4, 16, 36]
  |> somme                          // 56
}

Ce Que Vous Avez Compris

En écrivant map et filter à la main, vous avez remarqué qu'elles suivent le même schéma que toutes vos fonctions récursives :

case lst {
  Vide -> cas_de_base
  Cons(tete, queue) -> combiner(tete, récursion(queue))
}

Ce pattern a un nom en mathématiques : catamorphisme. En pratique, il est capturé par une fonction appelée fold. C'est une abstraction puissante, mais ce n'est pas l'objet de ce cours. Ce qui compte ici : vous en avez compris l'essence en l'écrivant vous-mêmes.


Résumé

Concept Syntaxe Rôle
Lambda fn(x) { ... } Fonction sans nom, sur place
Fonction d'ordre supérieur fn(f: fn(a) -> b, ...) Prend une fonction en paramètre
map map(fn(x) { ... }, lst) Transforme chaque élément
filter filter(fn(x) { ... }, lst) Garde certains éléments

Le Pattern

lst
|> filter(fn(x) { condition })   // sélectionne
|> map(fn(x) { transformation }) // transforme
|> résultat                       // agrège