Numérique et Sciences Informatiques > Langages de Programmation > Paradigmes de Programmation > Programmation fonctionnelle (notions de base)

Introduction à la Programmation Fonctionnelle

Découvrez les bases de la programmation fonctionnelle, un paradigme puissant et élégant, idéal pour aborder des problèmes complexes avec clarté et concision. Ce guide est spécialement conçu pour les élèves de lycée en Numérique et Sciences Informatiques (NSI).

Qu'est-ce que la programmation fonctionnelle ?

La programmation fonctionnelle est un paradigme de programmation où les programmes sont construits en appliquant et en composant des fonctions. Contrairement à la programmation impérative, qui se concentre sur la modification de l'état du programme à travers des instructions, la programmation fonctionnelle met l'accent sur les expressions et les transformations de données. En programmation fonctionnelle, on évite autant que possible les effets de bord et l'état mutable.

Principales caractéristiques:

  • Fonctions pures: Une fonction pure retourne toujours le même résultat pour les mêmes arguments et n'a pas d'effets de bord (elle ne modifie pas l'état extérieur).
  • Immutabilité: Les données ne sont pas modifiées après leur création. Les opérations créent de nouvelles données au lieu de modifier les existantes.
  • Fonctions de première classe: Les fonctions peuvent être traitées comme n'importe quelle autre valeur: passées en argument, retournées par d'autres fonctions, stockées dans des variables.
  • Récursion: Utilisation fréquente de la récursion pour réaliser des boucles et des traitements itératifs.

Fonctions pures

Une fonction pure est le pilier de la programmation fonctionnelle. Elle est définie par deux règles essentielles :

  1. Elle retourne toujours le même résultat si elle reçoit les mêmes arguments. Cela signifie qu'elle ne dépend que de ses arguments d'entrée.
  2. Elle n'a pas d'effets de bord. En d'autres termes, elle ne modifie pas l'état extérieur au programme (par exemple, elle ne modifie pas une variable globale, n'écrit pas dans un fichier, ou n'affiche rien à l'écran).

Exemple en Python (illustrant une fonction pure et une fonction impure):


# Fonction pure
def addition(a, b):
    return a + b

# Fonction impure (car elle utilise une variable globale)
global_result = 0
def impure_addition(a, b):
    global global_result
    global_result = a + b
    return global_result

# Fonction impure (car elle affiche quelque chose)
def afficher_addition(a, b):
    result = a + b
    print(f"{a} + {b} = {result}")
    return result

print(addition(2, 3)) # Affiche 5
impure_addition(2,3) # Modifie global_result, donc c'est impure.
print(global_result) # Affiche 5
afficher_addition(2, 3) # Affiche 2 + 3 = 5

La fonction addition est pure car elle dépend uniquement de a et b et ne modifie rien d'autre. Les fonctions impure_addition et afficher_addition ne sont pas pures.

Immutabilité

L'immutabilité signifie qu'une fois qu'une donnée est créée, elle ne peut plus être modifiée. Au lieu de modifier une donnée existante, on en crée une nouvelle, basée sur l'ancienne.

Exemple en Python (illustrant l'immutabilité des tuples et la mutabilité des listes):


# Tuple (immutable)
tuple_exemple = (1, 2, 3)
# tuple_exemple[0] = 4  # Ceci provoquerait une erreur car les tuples sont immutables

# Liste (mutable)
liste_exemple = [1, 2, 3]
liste_exemple[0] = 4  # Ceci est valide, la liste est modifiée
print(liste_exemple) # Affiche [4, 2, 3]

En programmation fonctionnelle, on préfère utiliser des structures de données immuables. Si l'on doit modifier une liste, on ne modifie pas la liste existante, mais on crée une nouvelle liste avec les modifications.

Fonctions de première classe

En programmation fonctionnelle, les fonctions sont traitées comme des valeurs de première classe. Cela signifie qu'elles peuvent être :

  • Assignées à des variables
  • Passées en argument à d'autres fonctions
  • Retournées par d'autres fonctions

Cette capacité permet de créer des fonctions d'ordre supérieur, c'est-à-dire des fonctions qui prennent d'autres fonctions en argument ou qui retournent des fonctions.

Exemple en Python :


def appliquer_operation(fonction, a, b):
    return fonction(a, b)

def addition(a, b):
    return a + b

def multiplication(a, b):
    return a * b

resultat_addition = appliquer_operation(addition, 5, 3)  # resultat_addition vaut 8
resultat_multiplication = appliquer_operation(multiplication, 5, 3)  # resultat_multiplication vaut 15

print(resultat_addition)
print(resultat_multiplication

Dans cet exemple, appliquer_operation est une fonction d'ordre supérieur qui prend une autre fonction (addition ou multiplication) en argument.

Récursion

La récursion est une technique de programmation où une fonction s'appelle elle-même pour résoudre un problème. C'est une alternative aux boucles (for, while) en programmation impérative.

Pour éviter une boucle infinie, une fonction récursive doit avoir une condition d'arrêt, c'est-à-dire une condition qui, lorsqu'elle est remplie, arrête les appels récursifs.

Exemple en Python (calcul de la factorielle d'un nombre) :


def factorielle(n):
    if n == 0:
        return 1  # Condition d'arrêt
    else:
        return n * factorielle(n - 1)  # Appel récursif

print(factorielle(5)) # Affiche 120

Dans cet exemple, la fonction factorielle s'appelle elle-même avec un argument plus petit jusqu'à ce que n soit égal à 0. La condition n == 0 est la condition d'arrêt.

Avantages de la programmation fonctionnelle

La programmation fonctionnelle offre plusieurs avantages :

  • Code plus concis et lisible: L'accent mis sur les fonctions et les expressions peut rendre le code plus clair et plus facile à comprendre.
  • Moins d'erreurs: L'absence d'effets de bord et l'immutabilité réduisent les risques d'erreurs liées à la modification de l'état du programme.
  • Facilité de test: Les fonctions pures sont plus faciles à tester car elles retournent toujours le même résultat pour les mêmes arguments.
  • Parallélisation facile: Les fonctions pures peuvent être exécutées en parallèle sans risque de conflits d'état.

Exemple concret : Calcul de la somme des carrés des nombres pairs d'une liste

Voici un exemple qui illustre plusieurs concepts de la programmation fonctionnelle en Python.


def est_pair(n):
    return n % 2 == 0

def carre(n):
    return n * n

def somme_carres_pairs(liste_nombres):
    # Filtrer les nombres pairs
    nombres_pairs = list(filter(est_pair, liste_nombres))
    # Calculer le carré de chaque nombre pair
    carres_pairs = list(map(carre, nombres_pairs))
    # Calculer la somme des carrés
    somme = sum(carres_pairs)
    return somme

liste_exemple = [1, 2, 3, 4, 5, 6]
resultat = somme_carres_pairs(liste_exemple)
print(resultat)  # Affiche 56 (2^2 + 4^2 + 6^2 = 4 + 16 + 36 = 56)

Explication:

  • est_pair et carre sont des fonctions pures.
  • filter et map sont des fonctions d'ordre supérieur.
  • La fonction somme_carres_pairs utilise ces fonctions pour réaliser le calcul de manière claire et concise.

Ce qu'il faut retenir

  • La programmation fonctionnelle est un paradigme basé sur les fonctions pures, l'immutabilité, et les fonctions de première classe.
  • Les fonctions pures retournent toujours le même résultat pour les mêmes arguments et n'ont pas d'effets de bord.
  • L'immutabilité signifie que les données ne sont pas modifiées après leur création.
  • Les fonctions de première classe peuvent être assignées à des variables, passées en argument, et retournées par d'autres fonctions.
  • La récursion est une alternative aux boucles en programmation impérative.
  • La programmation fonctionnelle offre des avantages tels que le code plus concis, moins d'erreurs, la facilité de test, et la parallélisation facile.

FAQ

  • Quelle est la différence entre programmation fonctionnelle et programmation impérative ?

    La programmation impérative se concentre sur la modification de l'état du programme en exécutant des instructions étape par étape, tandis que la programmation fonctionnelle se concentre sur l'application et la composition de fonctions sans modifier l'état du programme.
  • Est-ce que la programmation fonctionnelle est plus difficile que la programmation impérative ?

    Cela dépend de l'expérience et des préférences de chacun. La programmation fonctionnelle peut sembler plus abstraite au début, mais elle peut conduire à un code plus clair et plus facile à maintenir à long terme.
  • Quels sont les langages de programmation qui supportent la programmation fonctionnelle ?

    De nombreux langages de programmation supportent la programmation fonctionnelle, notamment Python, JavaScript, Haskell, Lisp, Clojure, Scala, et F#.