Retour au blog

OCaml en MP2I : Programmation Fonctionnelle

Découvre OCaml, le langage clé de la programmation fonctionnelle en MP2I, et développe une pensée algorithmique rigoureuse.

Cet article a été rédigé à des fins pédagogiques. Les informations présentées peuvent évoluer. Nous t’invitons à vérifier auprès de sources officielles.

Objectifs du cours :

  • Comprendre les principes fondamentaux de la programmation fonctionnelle.
  • Maîtriser la syntaxe de base d'OCaml et ses types de données.
  • Utiliser la récursivité et le filtrage par motif (pattern matching) pour résoudre des problèmes.
  • Manipuler les structures de données récursives comme les listes et les arbres.
  • Organiser son code avec les modules et les signatures.
  • Développer une approche algorithmique rigoureuse spécifique à la programmation fonctionnelle.

Prérequis :

  • Notions de base en logique et en mathématiques discrètes.
  • Familiarité avec la notion d'algorithme et de fonction.
  • Curiosité pour la programmation et la résolution de problèmes.
  • Une première expérience en programmation (même minime, ex: Python) est un plus mais pas obligatoire.

Bonjour à toi, futur expert en informatique ! En entrant en MP2I, tu t'apprêtes à découvrir un monde fascinant, et OCaml sera ton premier guide. Ce langage de programmation est au cœur de ton programme et t'initiera à la puissance de la programmation fonctionnelle.

OCaml, avec sa rigueur et sa clarté, t'apprendra à penser différemment les problèmes algorithmiques. Oublie les boucles et les variables mutables de certains langages : ici, la fonction est reine, et l'élégance de la récursivité te mènera vers des solutions concises et robustes.

Prêt à relever le défi ? Ce cours structuré t'accompagnera pas à pas pour maîtriser OCaml et développer une logique de programmation essentielle pour ta réussite en CPGE.

I. Découverte d'OCaml en MP2I : Un Monde Fonctionnel

L'informatique en CPGE MP2I est une discipline exigeante qui demande une grande rigueur. OCaml est le langage choisi pour t'enseigner les fondements de la programmation, notamment via le paradigme fonctionnel. Mais qu'est-ce que cela signifie, et pourquoi OCaml ?

Ce langage n'est pas seulement un outil, c'est une façon de penser. Il t'aidera à écrire du code plus sûr, plus lisible et plus facile à tester. Il te préparera aussi à des concepts avancés que tu rencontreras plus tard dans tes études d'ingénieur.

I.1. Qu'est-ce que la Programmation Fonctionnelle ?

La programmation fonctionnelle est un paradigme de programmation où le calcul est traité comme l'évaluation de fonctions mathématiques. Elle met l'accent sur les fonctions pures, l'immuabilité des données et l'absence d'effets de bord.

Cela contraste avec la programmation impérative, où tu décris pas à pas comment modifier l'état d'un programme. En fonctionnel, tu décris ce que tu veux calculer, sans te soucier des changements d'état.

Définition : Programmation Fonctionnelle
Un paradigme de programmation qui traite le calcul comme l'évaluation de fonctions mathématiques. Il favorise l'immuabilité des données, les fonctions pures (sans effets de bord) et la récursivité.

Définition : Fonction Pure
Une fonction pure est une fonction qui, pour les mêmes entrées, produit toujours la même sortie, et n'a aucun effet de bord (elle ne modifie pas l'état du programme en dehors de son propre retour de valeur).

Les avantages des fonctions pures sont nombreux. Elles sont plus faciles à raisonner, à tester et à paralléliser. L'absence d'effets de bord rend le code moins sujet aux bugs.

OCaml n'est pas un langage purement fonctionnel, il est "multi-paradigme", c'est-à-dire qu'il permet aussi la programmation impérative. Cependant, l'approche fonctionnelle est fortement encouragée et privilégiée en MP2I.

I.2. Pourquoi OCaml en MP2I ?

OCaml (Objective Caml) est un langage de la famille ML (Meta Language). Il est réputé pour son système de types fort et son inférence de types.

Ce langage est un excellent choix pédagogique car il force à la rigueur. Son compilateur est très exigeant et t'aide à détecter les erreurs avant même l'exécution.

Le savais-tu : OCaml est utilisé dans l'industrie pour des applications critiques, notamment dans la finance, la preuve de programmes, et le développement de compilateurs. C'est un langage avec des capacités sérieuses.

L'inférence de types te permet d'écrire du code sans déclarer explicitement tous les types, car le compilateur les déduit. Cela rend le code concis tout en garantissant une grande sécurité typographique.

En MP2I, OCaml t'apprendra la gestion de la mémoire, la récursivité, les structures de données complexes et la conception d'algorithmes efficaces. C'est une excellente base pour tout informaticien.

À retenir : La programmation fonctionnelle traite les calculs comme des fonctions mathématiques, privilégiant les fonctions pures et l'immuabilité. OCaml est un langage multi-paradigme, idéal en MP2I pour sa rigueur, son inférence de types et sa capacité à t'enseigner des bases solides en algorithmique.

II. Les Bases de la Syntaxe OCaml et Types Primitifs

Pour commencer à programmer en OCaml, tu dois te familiariser avec sa syntaxe et ses types de données de base. Chaque langage a ses particularités, et OCaml ne fait pas exception.

Comprendre comment déclarer des valeurs, manipuler des nombres et des caractères est la première étape vers la création de programmes fonctionnels. La précision de la syntaxe est essentielle.

II.1. Déclarations de Valeurs et Expressions

En OCaml, tu ne définis pas des "variables" au sens mutable du terme, mais des "valeurs" (ou des "liens"). Une fois qu'une valeur est associée à un nom, elle ne peut plus être modifiée. C'est le principe d'immuabilité.

La déclaration de valeurs se fait avec le mot-clé let. Chaque instruction est terminée par un double-point-virgule ;; dans l'interpréteur ou un simple point-virgule ; dans un bloc let ... in ....

Syntaxe de déclaration de valeur :
let nom_valeur = expression ;;

Les expressions sont des morceaux de code qui produisent une valeur. En OCaml, presque tout est une expression. Cela rend le langage très uniforme et puissant.

Par exemple, 1 + 2 est une expression qui évalue à 3. if x > 0 then "positif" else "négatif" est une expression qui renvoie une chaîne de caractères.

II.2. Types Primitifs : Int, Float, Bool, Char, String

OCaml est un langage fortement typé. Cela signifie que chaque valeur a un type, et le compilateur vérifie la cohérence des types. Cependant, grâce à l'inférence de types, tu n'as pas souvent besoin de les écrire.

Les types primitifs sont les briques de base pour construire des types plus complexes. Les connaître est fondamental pour comprendre comment OCaml manipule les données.

Type Description Exemples
int Nombres entiers 0, 42, -10
float Nombres à virgule flottante 3.14, 0.0, -2.5
bool Valeurs booléennes (vrai/faux) true, false
char Caractères uniques 'a', 'B', ' '
string Chaînes de caractères "hello", "OCaml"

Erreur fréquente :
Ne confonds pas les opérateurs pour les entiers et les flottants en OCaml. Par exemple, + est pour les entiers, mais +. est pour les flottants. Si tu mélanges, le compilateur te signalera une erreur de type !

Exemple : 3 + 2.5 est une erreur. Il faut écrire float_of_int 3 +. 2.5 ou 3.0 +. 2.5.

Exemple 1 : Déclarations et expressions avec types

Question : Déclare les valeurs suivantes en OCaml et observe leur type inféré.

  • x = 10
  • y = 3.14
  • est_vrai = true
  • message = "Bonjour"
  • resultat = x * 2 (avec x déjà défini)
  • division = y /. 2.0 (avec y déjà défini)

Résolution :

Étape 1 : Déclarer les valeurs.

let x = 10 ;;
(* val x : int = 10 *)

let y = 3.14 ;;
(* val y : float = 3.14 *)

let est_vrai = true ;;
(* val est_vrai : bool = true *)

let message = "Bonjour" ;;
(* val message : string = "Bonjour" *)

Étape 2 : Utiliser les valeurs dans des expressions.

let resultat = x * 2 ;;
(* val resultat : int = 20 *)

let division = y /. 2.0 ;;
(* val division : float = 1.57 *)

Le compilateur OCaml infère automatiquement le type de chaque valeur, ce qui est très pratique. Tu peux voir les types int, float, bool et string apparaître.

À retenir : En OCaml, tu déclares des valeurs immuables avec let. Chaque valeur a un type (inféré par le compilateur). Attention aux opérateurs différents pour les entiers (+, ) et les flottants (+., .).

III. Fonctions, Récursivité et Pattern Matching

Les fonctions sont le cœur de la programmation fonctionnelle en OCaml. Tu apprendras à les définir, à les appliquer et à les composer. La récursivité est la méthode privilégiée pour itérer sur les structures de données.

Le filtrage par motif (pattern matching) est une fonctionnalité très puissante d'OCaml qui te permet d'écrire des fonctions concises et robustes pour gérer différents cas de figure.

III.1. Définition et Application des Fonctions

Une fonction en OCaml prend des arguments et renvoie une valeur. Comme les autres valeurs, une fonction est immuable. Tu la définis une fois, et son comportement reste constant.

Les fonctions sont des citoyens de première classe en OCaml, ce qui signifie qu'elles peuvent être passées en argument à d'autres fonctions, ou renvoyées comme résultat. C'est une caractéristique clé du paradigme fonctionnel.

Syntaxe de définition de fonction :
let nom_fonction argument1 argument2 ... = expression_du_corps ;;

ou pour les fonctions anonymes :
fun argument1 argument2 ... -> expression_du_corps

L'application de fonctions se fait simplement en écrivant le nom de la fonction suivi de ses arguments. Pas besoin de parenthèses pour les appels de fonctions simples.

Par exemple, pour appeler une fonction addition avec les arguments a et b, tu écrirais addition a b.

III.2. La Récursivité : Penser sans Boucles

En programmation fonctionnelle, la récursivité remplace souvent les boucles (for, while) des langages impératifs. Une fonction récursive est une fonction qui s'appelle elle-même pour résoudre des problèmes de plus petite taille.

Pour qu'une fonction récursive soit correcte, elle doit avoir un cas de base (ou cas d'arrêt) qui ne fait pas d'appel récursif, et un cas récursif qui se rapproche du cas de base.

Définition : Récursivité
Méthode de résolution d'un problème où la solution est définie en fonction de solutions à des instances plus petites du même problème. En OCaml, une fonction récursive doit être précédée du mot-clé rec.

Syntaxe de fonction récursive :
let rec nom_fonction argument = ... nom_fonction (argument_plus_petit) ... ;;

Erreur fréquente :
Oublier le mot-clé rec pour les fonctions récursives. Si tu définis let factorielle n = ... factorielle (n-1) ... sans rec, OCaml pensera que factorielle est une nouvelle variable dans le corps de la fonction, et non un appel récursif à la fonction elle-même. Cela peut entraîner des erreurs de compilation ou des comportements inattendus.

III.3. Le Filtrage par Motif (Pattern Matching)

Le pattern matching est une fonctionnalité élégante d'OCaml qui permet de décomposer des valeurs complexes (comme des listes, des tuples ou des types définis par l'utilisateur) et d'exécuter du code différent en fonction de leur structure.

Il se fait généralement avec le mot-clé match ... with .... C'est une alternative puissante aux longues chaînes de if-then-else.

Syntaxe du pattern matching :
match expression_a_filtrer with
| pattern1 -> resultat1
| pattern2 -> resultat2
| _ -> resultat_par_defaut ;;

Exemple 2 : Fonction récursive et pattern matching (factorielle)

Question : Écris une fonction OCaml récursive factorielle qui calcule la factorielle d'un entier $n$. Utilise le pattern matching pour le cas de base.

Rappel : $0! = 1$ et $n! = n \times (n-1)!$ pour $n > 0$.

Résolution :

Étape 1 : Identifier le cas de base.
Le cas de base est $n=0$, où $0! = 1$.

Étape 2 : Identifier le cas récursif.
Pour $n > 0$, $n! = n \times (n-1)!$.

Étape 3 : Écrire la fonction en OCaml avec let rec et match ... with.

let rec factorielle n =
match n with
| 0 -> 1
| _ when n > 0 -> n * (factorielle (n - 1))
| _ -> failwith "La factorielle est définie pour les entiers positifs." ;;

Tests :
factorielle 0 ;; (* Résultat: 1 *)
factorielle 1 ;; (* Résultat: 1 *)
factorielle 5 ;; (* Résultat: 120 *)

Cette fonction est élégante et gère clairement les différents cas.

À retenir : Les fonctions en OCaml sont des valeurs immuables, souvent récursives (avec let rec). Le pattern matching (match ... with) est essentiel pour gérer différents cas de figure et décomposer des structures de données, rendant le code plus lisible et robuste.

IV. Structures de Données Fondamentales en OCaml

La programmation ne se limite pas aux calculs ; elle concerne aussi la manière d'organiser et de manipuler les données. OCaml offre plusieurs structures de données de base qui te permettent de représenter des collections d'informations.

Les listes sont particulièrement importantes en programmation fonctionnelle, mais tu rencontreras aussi les tuples, les tableaux et la création de tes propres types personnalisés.

IV.1. Tuples, Listes et Tableaux

Ces trois structures sont fondamentales pour regrouper des données. Chacune a ses spécificités et ses cas d'utilisation préférés.

Syntaxe des structures de données :

  • Tuple : (element1, element2, ...)
  • Liste : [element1; element2; ...] ou element :: reste_de_la_liste (opérateur de cons)
  • Tableau : [|element1; element2; ...|]

La liste vide est notée []. L'opérateur :: (cons) permet de construire une liste en ajoutant un élément en tête d'une autre liste. Par exemple, 1 :: [2; 3] donne [1; 2; 3].

Les tableaux sont utiles quand tu as besoin d'un accès rapide par index ou d'une modification in-place, mais leur utilisation rompt un peu avec le paradigme fonctionnel pur d'immuabilité.

IV.2. Types Algébriques de Données (Types Disjoints)

Les types algébriques de données (ADT) sont une fonctionnalité très puissante d'OCaml qui te permet de définir tes propres types complexes en combinant d'autres types. Ils sont idéaux pour représenter des structures arborescentes ou des données qui peuvent prendre différentes formes.

Tu peux définir des types "somme" (énumérations ou variantes) ou des types "produit" (enregistrements ou structs).

Syntaxe des types algébriques :

  • Type somme (variante) :
    type nom_type = Constructeur1 | Constructeur2 of type1 | Constructeur3 of type2 * type3 ;;
  • Type produit (enregistrement) :
    type nom_enregistrement = { champ1 : type1; champ2 : type2; } ;;

Les types algébriques sont souvent utilisés avec le pattern matching pour traiter élégamment les différentes variantes. C'est une combinaison très efficace pour écrire du code robuste.

Par exemple, tu pourrais définir un type forme qui peut être soit un cercle, soit un rectangle, avec des données différentes pour chaque cas.

Exemple 3 : Manipulation de listes et types algébriques

Question :

  1. Définis un type point représentant un point 2D avec ses coordonnées entières x et y.
  2. Définis un type forme qui peut être soit un Cercle (avec un point et un rayon entier), soit un Rectangle (avec deux points pour les coins opposés).
  3. Écris une fonction aire_forme qui calcule l'aire d'une forme donnée. (Pour un cercle, l'aire est $\pi r^2$, pour un rectangle c'est $|(x_2-x_1) \times (y_2-y_1)|$). Utilise 3.14 pour $\pi$.

Résolution :

Étape 1 : Définir le type point.

type point = { x : int; y : int };;
(* type point = { x : int; y : int; } *)

Étape 2 : Définir le type forme.

type forme = Cercle of point * int | Rectangle of point * point ;;
(* type forme = Cercle of point * int | Rectangle of point * point *)

Étape 3 : Écrire la fonction aire_forme.

let aire_forme f =
match f with
| Cercle ({x=_; y=_}, r) -> 3.14 . (float_of_int r) . (float_of_int r)
| Rectangle ({x=x1; y=y1}, {x=x2; y=y2}) ->
let largeur = abs (x2 - x1) in
let hauteur = abs (y2 - y1) in
float_of_int (largeur * hauteur) ;;

Tests :
let p1 = {x=0; y=0} ;;
let p2 = {x=3; y=4} ;;
let cercle1 = Cercle (p1, 2) ;;
let rect1 = Rectangle (p1, p2) ;;
aire_forme cercle1 ;; (* Résultat: 12.56 *)
aire_forme rect1 ;; (* Résultat: 12.0 *)

Cet exemple montre la puissance de la combinaison des types algébriques et du pattern matching pour gérer des données structurées.

À retenir : OCaml propose les tuples (éléments hétérogènes, taille fixe), les listes (éléments homogènes, taille variable, récursif) et les tableaux (éléments homogènes, taille fixe, mutable). Les types algébriques (type ... = ...) sont essentiels pour définir tes propres structures de données complexes et les manipuler avec le pattern matching.

V. Modules et Gestion de la Complexité

Au fur et à mesure que tes programmes deviennent plus grands et plus complexes, il devient essentiel de les organiser de manière logique. En OCaml, c'est le rôle des modules.

Les modules te permettent de regrouper des fonctions et des types liés, d'encapsuler des détails d'implémentation et de fournir une interface claire. C'est un pilier de la modularité et de la réutilisabilité du code.

V.1. Principes des Modules et Signatures

Un module en OCaml est une unité de compilation qui contient un ensemble de définitions (fonctions, types, valeurs). Chaque fichier .ml correspond généralement à un module.

Les modules sont essentiels pour structurer un projet et éviter les conflits de noms. Ils améliorent la lisibilité et la maintenance du code, surtout dans les projets d'équipe.

Définition : Module
Un module en OCaml est une unité organisationnelle qui regroupe des définitions (types, valeurs, fonctions). Il permet d'encapsuler le code et de gérer sa visibilité.

Chaque module peut avoir une signature, un fichier .mli correspondant, qui déclare l'interface publique du module. La signature spécifie ce qui est visible de l'extérieur du module et quels sont les types des fonctions exposées.

La signature est comme un "contrat" : elle garantit que l'implémentation du module respecte l'interface promise. Cela facilite la collaboration et la conception de bibliothèques.

Exemple de module et signature :

  • Fichier Calculateur.mli (signature) :
    val addition : int -> int -> int
    val soustraction : int -> int -> int
  • Fichier Calculateur.ml (implémentation) :
    let addition x y = x + y
    let soustraction x y = x - y
    let multiplication x y = x * y (* non visible de l'extérieur *)

Quand tu utilises un module, tu peux soit qualifier les noms (Calculateur.addition 5 3), soit ouvrir le module (open Calculateur;;) pour utiliser directement les noms (addition 5 3).

Il est généralement recommandé de qualifier les noms pour éviter les ambiguïtés, sauf si le module est très fréquemment utilisé et que les noms sont uniques.

V.2. Foncteurs : Modules Paramétrés

Les foncteurs sont un concept avancé en OCaml mais très puissant. Un foncteur est une fonction qui prend un ou plusieurs modules en argument et renvoie un nouveau module.

Ils permettent de créer des modules génériques qui peuvent être adaptés à différentes implémentations. C'est l'équivalent des "génériques" ou "templates" dans d'autres langages, mais au niveau des modules.

Définition : Foncteur
Un foncteur est une construction OCaml qui prend un ou plusieurs modules en argument (conformes à certaines signatures) et renvoie un nouveau module. Il permet de construire des composants logiciels génériques.

Les foncteurs sont utiles pour implémenter des structures de données abstraites (comme les listes, les arbres, les ensembles) de manière générique, indépendamment du type d'éléments qu'elles contiennent. Tu peux ainsi créer un module "Set" qui fonctionne pour des entiers, des chaînes de caractères, etc.

Bien que plus complexes, les foncteurs sont au cœur de la bibliothèque standard d'OCaml et sont un exemple de la flexibilité du système de modules du langage. Tu les aborderas probablement en deuxième année de prépa.

À retenir : Les modules (fichiers .ml) permettent d'organiser ton code et d'encapsuler des définitions. Les signatures (fichiers .mli) définissent l'interface publique d'un module, garantissant la cohérence. Les foncteurs sont des fonctions de modules à modules, offrant une généricité avancée.

VI. Algorithmique et Programmation Fonctionnelle

La programmation fonctionnelle en OCaml t'incite à aborder les problèmes algorithmiques avec une perspective différente. Plutôt que de manipuler des états, tu te concentres sur la transformation des données via des fonctions.

Cette approche favorise des algorithmes plus déclaratifs, souvent exprimés de manière récursive. Nous allons explorer comment OCaml gère les boucles implicites et les concepts clés pour l'efficience.

VI.1. Penser Récursif pour les Algorithmes

Beaucoup d'algorithmes classiques sont naturellement exprimés en termes récursifs. La récursivité est très puissante pour parcourir des structures de données récursives comme les listes ou les arbres.

Il est crucial d'identifier le cas de base et la relation de récurrence pour chaque problème. Une bonne définition de ces éléments est la clé d'un algorithme récursif correct.

Définition : Récursivité Terminale (Tail Recursion)
Une fonction récursive est dite terminale si l'appel récursif est la dernière opération effectuée dans le corps de la fonction. OCaml optimise ces fonctions pour qu'elles s'exécutent aussi efficacement qu'une boucle itérative, sans risquer un débordement de pile.

La récursivité terminale est une optimisation essentielle à connaître. Elle permet d'écrire des fonctions récursives sans craindre d'épuiser la mémoire de la pile d'appels (stack overflow) pour de grandes entrées.

Pour rendre une fonction récursive terminale, tu dois souvent introduire un "accumulateur" qui stocke le résultat intermédiaire, et le passer d'un appel récursif à l'autre.

VI.2. Tris et Recherches en OCaml

Les algorithmes de tri et de recherche sont des classiques de l'informatique. Tu les reverras en OCaml, en mettant l'accent sur les implémentations fonctionnelles et récursives.

Comprendre comment implémenter un tri par insertion ou une recherche dichotomique de manière récursive est un excellent exercice pour maîtriser OCaml.

VI.2.1. Tri par Insertion Récursif

Le tri par insertion est un algorithme de tri simple. En OCaml, il se prête bien à une implémentation récursive sur les listes.

L'idée est d'insérer chaque élément de la liste non triée à sa bonne place dans la partie déjà triée.

Exemple 4 : Tri par insertion sur une liste d'entiers

Question : Écris une fonction OCaml insertion qui insère un entier dans une liste d'entiers triée, et une fonction tri_insertion qui trie une liste d'entiers en utilisant insertion.

Résolution :

Étape 1 : Fonction insertion (récursive).

let rec insertion x liste_triee =
match liste_triee with
| [] -> [x] (* Cas de base : insérer dans une liste vide *)
| tete :: queue ->
if x <= tete then x :: liste_triee (* Si x est plus petit, on l'insère ici *)
else tete :: (insertion x queue) ;; (* Sinon, on cherche plus loin *)

Étape 2 : Fonction tri_insertion (récursive).

let rec tri_insertion liste =
match liste with
| [] -> [] (* Cas de base : une liste vide est déjà triée *)
| tete :: queue -> insertion tete (tri_insertion queue) ;;

Tests :
tri_insertion [3; 1; 4; 1; 5; 9; 2; 6] ;; (* Résultat: [1; 1; 2; 3; 4; 5; 6; 9] *)

Ces fonctions illustrent bien l'élégance de la récursivité et du pattern matching pour manipuler les listes.

À retenir : En fonctionnel, la récursivité est la méthode privilégiée pour les algorithmes, surtout avec les listes et les arbres. La récursivité terminale est une optimisation essentielle pour l'efficacité. Les algorithmes classiques comme le tri par insertion sont de bons exemples d'application de ces concepts en OCaml.

VII. Récapitulatif et Exercices d'Application

Félicitations pour avoir parcouru ce cours d'introduction à OCaml pour la MP2I ! Tu as découvert les principes de la programmation fonctionnelle, la syntaxe du langage, les structures de données clés et l'approche algorithmique.

OCaml est un langage exigeant mais très gratifiant. Il te fournit des bases solides pour penser de manière rigoureuse et écrire du code de qualité. N'hésite pas à revoir les concepts et à t'entraîner régulièrement.

VII.1. Synthèse des Concepts Clés

Voici un tableau récapitulatif des points essentiels à retenir de ce cours d'OCaml.

Concept Description Exemples OCaml
Paradigme Fonctionnel Calculs comme fonctions mathématiques, immuabilité, fonctions pures, pas d'effets de bord. let carre x = x * x ;;
Syntaxe de Base Déclarations avec let, expressions, inférence de types, opérateurs spécifiques (+ vs +.). let pi = 3.14 ;;
Types Primitifs int, float, bool, char, string. 10, 2.5, true, 'a', "texte"
Fonctions Citoyens de première classe, définition avec let, application sans parenthèses. let add a b = a + b ;;
Récursivité Solution par auto-appel, cas de base, let rec. Privilégiée sur les boucles. let rec fib n = ... ;;
Pattern Matching Décomposition de valeurs avec match ... with, gestion élégante des cas. match liste with [] -> ... | t::q -> ... ;;
Structures de Données Tuples, listes (::, []), tableaux ([|...|]). (1, "a"), [1;2;3], [|'a';'b'|]
Types Algébriques Définition de types personnalisés avec type (variantes, enregistrements). type couleur = Rouge | Vert | Bleu ;;
Modules Organisation du code (.ml), interfaces (.mli). module MonModule = struct ... end ;;

VII.2. Exercices d'Application Rapides

Entraîne-toi avec ces quelques exercices pour consolider tes connaissances d'OCaml.

Exercice 1 : Somme des éléments d'une liste

Écris une fonction OCaml récursive somme_liste qui prend en argument une liste d'entiers et renvoie la somme de ses éléments. Si la liste est vide, la somme est 0.

Solution Exercice 1 :

let rec somme_liste liste =
match liste with
| [] -> 0
| tete :: queue -> tete + (somme_liste queue) ;;

somme_liste [1; 2; 3; 4] ;; (* Résultat: 10 *)

Exercice 2 : Longueur d'une chaîne de caractères

Écris une fonction est_paire_longueur qui prend une chaîne de caractères en argument et renvoie true si sa longueur est paire, et false sinon. (Indice : utilise String.length et l'opérateur modulo mod).

Solution Exercice 2 :

let est_paire_longueur s =
(String.length s) mod 2 = 0 ;;

est_paire_longueur "hello" ;; (* Résultat: false *)
est_paire_longueur "OCaml" ;; (* Résultat: false *)
est_paire_longueur "course" ;; (* Résultat: true *)

Exercice 3 : Conversion de température

Écris une fonction OCaml celsius_vers_fahrenheit qui prend une température en degrés Celsius (float) et la convertit en degrés Fahrenheit (float). La formule est $F = C \times 1.8 + 32$.

Solution Exercice 3 :

let celsius_vers_fahrenheit c =
c *. 1.8 +. 32.0 ;;

celsius_vers_fahrenheit 0.0 ;; (* Résultat: 32.0 *)
celsius_vers_fahrenheit 25.0 ;; (* Résultat: 77.0 *)

Comment ORBITECH Peut T'aider

La programmation OCaml en MP2I peut sembler complexe au début, mais avec les bons outils, tu peux exceller. ORBITECH AI Academy te propose une suite d'outils spécialement conçus pour t'accompagner dans ta maîtrise de ce langage et des concepts algorithmiques.

Contenu en libre diffusion — partage autorisé sous réserve de mentionner ORBITECH AI Academy comme source.

OPTIMISE TA PROGRAMMATION OCAML

Des outils intelligents pour t'aider à coder, comprendre et exceller en OCaml.

Commencer gratuitement
🌍 ORBITECH AI Academy — Free education in 88 languages for 171 countries