Programmation fonctionnelle en Swift : de A à Z
La programmation fonctionnelle (PF) est un paradigme qui considère le calcul comme l'évaluation de fonctions mathématiques et évite les changements d'état et les données mutables. Swift, étant un langage multi-paradigme, supporte parfaitement le style fonctionnel, en particulier dans le développement pour iOS et macOS. Dans cet article, nous parcourrons le chemin des concepts de base aux techniques avancées, telles que les monades et la composition de fonctions.
Fondements de l'approche fonctionnelle en Swift
La programmation fonctionnelle repose sur plusieurs principes clés :
- Fonctions pures — le résultat dépend uniquement des arguments d'entrée, sans effets secondaires.
- Immutabilité des données — utilisation de
letau lieu devar. - Fonctions comme citoyens de première classe — elles peuvent être passées, retournées et stockées.
Regardons un exemple simple de fonction pure :
// Fonction pure : pas d'effets secondairesfunc add(_ a: Int, _ b: Int) -> Int { return a + b}
// Utilisationlet result = add(3, 5) // 8print(result)Closures et fonctions d'ordre supérieur
Les closures sont des blocs de fonctionnalités autonomes qui peuvent être passés et utilisés dans le code. Ils sont la base du travail avec les fonctions d'ordre supérieur.
// Closure simplelet multiply = { (x: Int, y: Int) -> Int in return x * y}
let product = multiply(4, 7) // 28print(product)Swift fournit de puissantes fonctions d'ordre supérieur pour travailler avec les collections :
map
map applique une transformation à chaque élément du tableau :
let numbers = [1, 2, 3, 4, 5]let squared = numbers.map { $0 * $0 }print(squared) // [1, 4, 9, 16, 25]filter
filter sélectionne les éléments qui satisfont une condition :
let evenNumbers = numbers.filter { $0 % 2 == 0 }print(evenNumbers) // [2, 4]reduce
reduce combine tous les éléments en une seule valeur :
let sum = numbers.reduce(0, +)print(sum) // 15Composition de fonctions et curryfication
La composition permet de combiner des fonctions simples en fonctions plus complexes. Swift n'a pas d'opérateur de composition intégré, mais il est facile à implémenter :
// Opérateur de compositionprecedencegroup CompositionPrecedence { associativity: left higherThan: AssignmentPrecedence}
infix operator >>>: CompositionPrecedence
func >>> <A, B, C>(left: @escaping (A) -> B, right: @escaping (B) -> C) -> (A) -> C { return { right(left($0)) }}
// Utilisationfunc double(_ x: Int) -> Int { x * 2 }func toString(_ x: Int) -> String { "\\(x)" }
let doubleThenString = double >>> toStringprint(doubleThenString(5)) // "10"La curryfication est la transformation d'une fonction prenant plusieurs arguments en une séquence de fonctions, chacune prenant un seul argument :
// Fonction normalefunc add(_ a: Int, _ b: Int) -> Int { a + b }
// Version curryfiéefunc curriedAdd(_ a: Int) -> (Int) -> Int { return { b in a + b }}
let addFive = curriedAdd(5)print(addFive(3)) // 8Monades et foncteurs en Swift
En programmation fonctionnelle, un foncteur est un type qui peut être transformé (map). Une monade est un foncteur avec une opération supplémentaire flatMap (ou >>=). L'exemple le plus connu en Swift est Optional et Array.
Optional comme monade
let optionalValue: Int? = 5
// map — applique une fonction si la valeur n'est pas nillet doubled = optionalValue.map { $0 * 2 }print(doubled) // Optional(10)
// flatMap