La programmation fonctionnelle n'est pas un paradigme. C'est une boîte à outils. La capacité de passer des fonctions comme arguments, de les retourner depuis d'autres fonctions et de les composer en pipelines n'est pas un exercice académique -- c'est la manière la plus pratique de transformer des données dans une application web.
La Session 177 a apporté les fonctions d'ordre supérieur à FLIN. Pas comme un import de bibliothèque. Pas comme une extension fonctionnelle boulonnée. Comme des méthodes intégrées sur chaque liste, avec une syntaxe lambda concise et une inférence de types complète. Le résultat : des pipelines de transformation de données qui se lisent comme de l'anglais, s'exécutent comme du code natif et attrapent les erreurs de type à la compilation.
Les trois fondamentales : Map, Where, Reduce
map : transformer chaque élément
flinnumbers = [1, 2, 3, 4, 5]
doubled = numbers.map(n => n * 2)
// [2, 4, 6, 8, 10]
users = User.all
names = users.map(u => u.name)
// ["Juste", "Thales", "Claude"]where : garder les éléments correspondants
FLIN utilise where au lieu de filter pour une raison délibérée : cela se lit plus naturellement en anglais. "Users where active" est une pensée complète. "Users filter active" ne l'est pas.
flinevens = numbers.where(n => n.is_even)
// [2, 4, 6, 8, 10]
adults = users.where(u => u.age >= 18)
active_admins = users.where(u => u.is_active and u.role == "admin")reduce : réduire une liste à une seule valeur
flinnumbers = [1, 2, 3, 4, 5]
total = numbers.reduce(0, (acc, n) => acc + n)
// 15
// Construire un map de fréquences
frequency = words.reduce({}, (acc, word) => {
count = acc.get(word, 0)
acc.set(word, count + 1)
})Au-delà des trois fondamentales
flin// flat_map : mapper et aplatir
users_orders = users.flat_map(u => u.orders)
// zip et zip_with : combiner deux listes
sentences = names.zip_with(ages, (name, age) => "{name} is {age}")
// partition : séparer en deux groupes
result = numbers.partition(n => n.is_even)
evens = result[0] // [2, 4, 6, 8, 10]
odds = result[1] // [1, 3, 5, 7, 9]
// group_by : catégoriser les éléments
by_role = users.group_by(u => u.role)
// chunk : découper en groupes de taille fixe
pages = items.chunk(3)
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]Chaînage de méthodes : le pattern pipeline
La vraie puissance des fonctions d'ordre supérieur émerge quand vous les chaînez :
flin// Trouver les 5 articles les plus chers achetés par des utilisateurs actifs ce mois-ci
result = orders
.where(o => o.user.is_active)
.where(o => o.created_at.is_after(now.start_of_month))
.flat_map(o => o.items)
.sort_by(item => item.price)
.reverse
.take(5)
.map(item => {
name: item.name,
price: item.price.format(2)
})Cette chaîne se lit de haut en bas comme un flux de données. Chaque étape produit une nouvelle liste. Aucune étape ne modifie les données originales. Le pipeline entier est immuable, prévisible et facile à déboguer.
Les douze fonctions d'ordre supérieur
| Fonction | Signature | But |
|---|---|---|
map | (T -> U) -> [U] | Transformer chaque élément |
where | (T -> bool) -> [T] | Garder les correspondants |
reject | (T -> bool) -> [T] | Supprimer les correspondants |
reduce | (U, (U,T) -> U) -> U | Réduire à une seule valeur |
flat_map | (T -> [U]) -> [U] | Mapper et aplatir |
find | (T -> bool) -> T? | Première correspondance ou none |
find_index | (T -> bool) -> int? | Index de la première correspondance |
any | (T -> bool) -> bool | True si au moins un correspond |
all | (T -> bool) -> bool | True si tous correspondent |
none_match | (T -> bool) -> bool | True si aucun ne correspond |
partition | (T -> bool) -> [[T],[T]] | Séparer en deux groupes |
group_by | (T -> K) -> map[K,[T]] | Grouper par clé |
Douze fonctions qui remplacent les boucles impératives dans 90 % du code de transformation de données. Chacune est une méthode intégrée sur chaque liste. Pas d'imports. Pas de bibliothèque de programmation fonctionnelle. Juste .map, .where et .reduce.
Ceci est la partie 78 de la série "How We Built FLIN", documentant comment un CEO à Abidjan et un CTO IA ont construit des fonctions d'ordre supérieur dans un langage de programmation avec inférence de types complète.
Navigation de la série : - [77] Introspection and Reflection at Runtime - [78] Reduce, Map, Filter: Higher-Order Functions (vous êtes ici) - [79] Validation and Sanitization Functions - [80] Error Tracking and Performance Monitoring