☀️ Stage Pré-rentrée · dès le 24 aoûtRéserver ma place →
Majorant
📘 Fiche de cours · 1re année💻 MP2I💻 Informatique MP2I / MPINiveau · MP2I

OCaml — n-uplets et enregistrements

Deux façons de regrouper des valeurs en OCaml : les n-uplets (accès par position — fst, snd, filtrage) et les enregistrements (accès par nom — p.x, et mise à jour fonctionnelle immuable p with x = … ) — construction et accès tracés, avec trois exercices corrigés.

Fiche rédigée par les mentors Majorant — alumni Polytechnique, CentraleSupélec et Mines Paris.

3 définitionsMis à jour le 2026-08-02

Vue d'ensemble

Jusqu'ici, une variable OCaml portait une seule valeur : un entier, un flottant, une chaîne. Mais un point du plan, c'est deux nombres ; un compte bancaire, c'est un nom et un solde. OCaml offre deux outils pour regrouper plusieurs valeurs en une seule : les n-uplets (couples, triplets…) et les enregistrements. La différence tient en un mot : dans un n-uplet on désigne une composante par sa position, dans un enregistrement par son nom.

Au programme. Construction d'un couple et d'un triplet ; type produit noté avec * (ex. int * string) ; extraction par filtrage let (a, b) = c in ... et fonctions fst / snd ; déclaration d'un type enregistrement type point = { x : int; y : int } ; accès à un champ par le point p.x ; mise à jour fonctionnelle { p with x = 5 } et immutabilité de la valeur d'origine.

Prérequis

  • Déclarer une valeur avec let et une valeur locale avec let ... in.
  • Connaître les types de base : int, float, bool, string.
  • Savoir lire un type de fonction (fiche ocaml-premiers-pas).
  • Distinguer la division entière / (sur int) des opérateurs flottants +. *. /..
🎯 Accompagnement Majorant

Bloqué dès la syntaxe OCaml ? Le fonctionnel déroute quand on vient du C. Nos mentors alumni X · Centrale · Mines t'apprennent à lire un type produit et à manipuler tuples et records sans te noyer dans les parenthèses.

Trouver un mentor →

Les n-uplets (tuples)

Un n-uplet regroupe un nombre fixe de valeurs, éventuellement de types différents, dans un ordre déterminé. On l'écrit entre parenthèses, composantes séparées par des virgules.

Définition 1.1 — n-uplet (tuple)

Un n-uplet est une valeur formée de composantes ordonnées . Son type est le type produit , noté en OCaml avec l'opérateur *. Un couple a , un triplet . Le nombre et l'ordre des composantes font partie du type : on ne peut ni en ajouter ni en retirer.

let origine = (0, 0)          (* couple, type int * int *)
let etudiant = ("Bob", 25, true)   (* triplet, type string * int * bool *)
let a = fst origine           (* première composante d'un couple *)
let b = snd origine           (* seconde composante d'un couple *)
🔍 Décryptage ligne par ligne
let origine = (0, 0)on lie origine à un couple de deux entiers ; OCaml lui donne le type int * int (« int fois int »), car les deux composantes sont des entiers.
let etudiant = ("Bob", 25, true)un triplet mélangeant trois types ; son type est string * int * bool. Les composantes peuvent être hétérogènes, contrairement à une liste où tous les éléments ont le même type.
let a = fst originefst (de first) renvoie la première composante d'un couple ; ici a vaut 0. Attention : fst ne fonctionne que sur un couple, pas sur un triplet.
let b = snd originesnd (de second) renvoie la seconde composante d'un couple ; ici b vaut 0.

Extraire par filtrage

Pour un triplet, ou tout simplement pour nommer d'un coup toutes les composantes, on utilise le filtrage : à gauche du =, on écrit un motif qui a la même forme que le n-uplet, et OCaml relie chaque nom à la composante correspondante.

let couple = (3, 4)
let (x, y) = couple in x * x + y * y   (* déballe le couple : x=3, y=4 *)
🔍 Décryptage ligne par ligne
let couple = (3, 4)on construit le couple (3, 4), de type int * int.
let (x, y) = couple in ...le motif (x, y) a la forme d'un couple : OCaml lie x à la première composante (3) et y à la seconde (4). C'est du filtrage de motif, pas une multiplication.
x * x + y * yon calcule . Le résultat de l'expression let ... in est donc 25.
💡 fst et snd ne sont que du filtrage déguisé. On pourrait définir soi-même let fst (a, _) = a et let snd (_, b) = b. Le caractère _ est un motif « joker » qui filtre sans nommer.
⚠ L'ordre des composantes compte. (3, 4) et (4, 3) sont deux valeurs différentes. Si tu écris let (y, x) = (3, 4), alors y vaut 3 et x vaut 4 : c'est la position qui décide, pas le nom que tu donnes. Une inversion silencieuse est un bug classique.

Les enregistrements (records)

Quand un objet a plusieurs champs, désigner chaque composante par sa position devient vite illisible (qui se souvient que la 4e composante est le solde ?). L'enregistrement résout cela : chaque composante porte un nom.

Définition 2.1 — enregistrement (record)

Un enregistrement est une valeur formée de plusieurs champs nommés. On déclare d'abord un type nommé qui liste les champs et leurs types, puis on construit des valeurs de ce type. On accède à un champ par la notation pointée valeur.champ.

type point = { x : int; y : int }   (* 1. déclaration du type *)
let p = { x = 1; y = 2 }            (* 2. construction d'une valeur *)
let abscisse = p.x                  (* 3. accès au champ x *)
🔍 Décryptage ligne par ligne
type point = { x : int; y : int }on déclare un nouveau type nommé point : tout point a un champ x entier et un champ y entier. Cette ligne ne crée aucune valeur, elle décrit une forme. Les champs sont séparés par ;.
let p = { x = 1; y = 2 }on construit une valeur de type point en donnant une valeur à chaque champ. L'ordre d'écriture des champs est libre : { y = 2; x = 1 } désigne exactement le même point.
let abscisse = p.xp.x lit le champ x de p ; ici abscisse vaut 1. On accède par le nom du champ, jamais par une position.

Mise à jour fonctionnelle

Les valeurs OCaml sont immuables : on ne modifie pas p, on fabrique une nouvelle valeur à partir de lui. La syntaxe { p with champ = ... } copie tous les champs de p et remplace seulement ceux qu'on cite.

Définition 2.2 — mise à jour fonctionnelle

L'expression { r with c = v } renvoie un nouvel enregistrement identique à r, sauf que le champ c y vaut v. L'enregistrement d'origine r n'est pas modifié : c'est une copie mise à jour, pas une affectation.

type point = { x : int; y : int }
let p = { x = 1; y = 2 }
let q = { p with x = 5 }   (* nouveau point : x remplacé, y copié *)
let ancien = p.x           (* p n'a pas changé *)
🔍 Décryptage ligne par ligne
let p = { x = 1; y = 2 }le point de départ : p.x = 1, p.y = 2.
let q = { p with x = 5 }OCaml copie tous les champs de p, puis écrase x avec 5. Résultat : q = { x = 5; y = 2 }. Le champ y non cité est repris tel quel.
let ancien = p.xp est intact : ancien vaut toujours 1. La mise à jour fonctionnelle n'a pas touché p, elle a produit une valeur distincte q.
📝 « with » ne mute rien. Malgré le mot-clé with qui évoque une modification, aucune case mémoire de p n'est réécrite. On obtient une seconde valeur ; p et q coexistent. Cette immutabilité est la règle par défaut en OCaml.
⚠ Le type doit être déclaré avant. Écrire let p = { x = 1; y = 2 } sans avoir déclaré au préalable un type possédant les champs x et y provoque une erreur : OCaml ne sait pas à quel type d'enregistrement rattacher ces champs. Toujours type ... = { ... } d'abord.

n-uplet ou enregistrement : lequel choisir ?

Les deux regroupent des valeurs, mais le mode d'accès diffère radicalement.

Comparaison des deux constructions
n-upletenregistrement
Déclaration de type préalablenonoui (type ... = { ... })
Écriture d'une valeur(1, 2){ x = 1; y = 2 }
Accès à une composantepar position : fst, snd, filtragepar nom : p.x
Lisibilité avec beaucoup de champsfaible (on compte les positions)forte (les noms parlent)
Mise à jour d'une composantereconstruire tout le n-uplet{ p with x = ... }
📐 Méthode — choisir la bonne structure
  1. Deux ou trois valeurs, usage local et évident (un couple (clé, valeur), un résultat de division (quotient, reste)) ? → un n-uplet, léger et sans déclaration.
  2. Plusieurs champs, ou champs faciles à confondre (deux int qui ne veulent pas dire la même chose) ? → un enregistrement, dont les noms empêchent les inversions.
  3. Besoin de « modifier » un champ souvent ? → enregistrement, grâce à { ... with ... }.

Table de trace : milieu de deux points

On calcule le milieu de deux points à coordonnées entières. On suit la construction des valeurs puis l'accès aux champs, pas à pas.

type point = { x : int; y : int }

let milieu a b =
  { x = (a.x + b.x) / 2;
    y = (a.y + b.y) / 2 }

let p1 = { x = 0; y = 0 }
let p2 = { x = 6; y = 4 }
let m = milieu p1 p2
let mx = m.x
🔍 Décryptage ligne par ligne
type point = { x : int; y : int }on déclare le type point à deux champs entiers, indispensable avant toute valeur.
let milieu a b = { x = (a.x + b.x) / 2; ... }fonction à deux arguments a et b (deux points) ; elle construit un nouveau point dont chaque coordonnée est la moyenne entière des coordonnées correspondantes. Le / est la division entière (troncature).
let p1 = { x = 0; y = 0 }premier point, à l'origine.
let p2 = { x = 6; y = 4 }second point.
let m = milieu p1 p2on applique milieu : a devient p1, b devient p2.
let mx = m.xon lit le champ x du milieu obtenu.
Exécution de milieu p1 p2 avec p1 = {x=0; y=0} et p2 = {x=6; y=4}
Étapea.xb.xa.yb.ycalcul du champvaleur construite
appel milieu p1 p20604
champ x06(0 + 6) / 2 = 3{ x = 3; ... }
champ y04(0 + 4) / 2 = 2{ x = 3; y = 2 }
résultat m{ x = 3; y = 2 }
accès m.xlecture du champ xmx = 3
⚠ Division entière sur les coordonnées. Avec p1 = {x=0} et p2 = {x=5}, le champ x du milieu vaut (0 + 5) / 2 = 2, et non 2.5 : / tronque. Pour un vrai milieu, il faudrait des float et l'opérateur /..
🎯 Accompagnement Majorant

Tuple, record, filtrage : tu confonds tout ? Un mentor alumni X · Centrale · Mines te fait manipuler ces structures sur tes propres exos jusqu'à ce que le choix devienne un réflexe.

Trouver un mentor →

Exercices corrigés

Exo 1Lire un coupleFacile

On pose let c = (7, 2). Que valent fst c, snd c, et l'expression let (a, b) = c in a - b ?

Voir la correction détaillée
fst c renvoie la première composante : 7.
snd c renvoie la seconde composante : 2.
Le filtrage let (a, b) = c lie a = 7 (position 1) et b = 2 (position 2). Donc a - b = 7 - 2 = 5.
Exo 2Déplacer un pointIntermédiaire

Avec type point = { x : int; y : int }, écris une fonction decale_x qui prend un point p et un entier d, et renvoie un point dont l'abscisse est augmentée de d, l'ordonnée inchangée. Vérifie que le point d'origine n'est pas modifié.

Voir la correction détaillée
On veut changer un seul champ : la mise à jour fonctionnelle est idéale.
let decale_x p d = { p with x = p.x + d }
{ p with x = p.x + d } copie y tel quel et remplace x par p.x + d.
Test : let p = { x = 1; y = 9 } puis let q = decale_x p 4 donne q = { x = 5; y = 9 }. Comme with ne mute pas, p.x vaut toujours 1 : l'original est intact.
Exo 3Somme des composantes d'un tripletDifficile

Un vecteur 3D est représenté par un triplet (float * float * float). Écris une fonction norme_carre qui renvoie le carré de la norme . Puis évalue norme_carre (1., 2., 2.).

Voir la correction détaillée
Un triplet ne se lit pas avec fst/snd (réservés aux couples) : on filtre.
let norme_carre (x, y, z) = x *. x +. y *. y +. z *. z
Le motif (x, y, z) déballe les trois composantes. On utilise les opérateurs flottants *. et +. car les composantes sont des float.
Évaluation de norme_carre (1., 2., 2.) : 9. (résultat flottant 9.).
Piège évité : écrire * au lieu de *. provoquerait une erreur de type, car * attend des int.

Récap final — Ce qu'il faut absolument retenir

Deux façons de regrouper des valeurs, deux modes d'accès. Coche mentalement chaque point.

  • Sais-tu écrire le type d'un couple et d'un triplet avec * (ex. int * string, string * int * bool) ?
  • Sais-tu que fst et snd ne marchent que sur un couple, et qu'un triplet s'extrait par filtrage let (a, b, c) = t ?
  • Sais-tu qu'un n-uplet s'accède par position et qu'inverser l'ordre change la valeur ?
  • Sais-tu qu'un enregistrement exige une type ... = { ... } déclarée avant toute valeur ?
  • Sais-tu construire { x = 1; y = 2 } (ordre des champs libre) et lire un champ avec p.x ?
  • Sais-tu que { p with x = 5 } renvoie un nouveau record et ne modifie pas p ?
  • Sais-tu choisir : n-uplet pour 2-3 valeurs locales, record dès qu'il y a plusieurs champs à nommer ?
  • Sais-tu que / sur les int tronque, et qu'un milieu exact demande des float et /. ?

Débloque la fiche complète

Théorèmes, démonstrations à savoir refaire, méthodes-types et pièges de concours : crée ton compte gratuit pour tout lire. Une seule fois pour toutes les fiches et ressources Majorant.

Gratuit · vos données restent confidentielles.

Valide tes acquis

Quiz — OCaml : tuples & records

11 questions · une à la fois · seuil de maîtrise 80 %.

MP2I / MPI · MP2IQuiz — OCaml — n-uplets et enregistrementsQuestion 1 / 11
FacileVrai / Faux1 pt

La valeur ("ok", 3) a pour type string * int en OCaml.

Sélectionne une réponse pour valider.

Fiches associées

💻 MP2I·Informatique

C — Premiers pas

Écrire son premier programme C : la structure main/return, les types de base, printf et ses formats, les boucles for/while, et le piège n°1 — la division entière (7/2 vaut 3, pas 3,5) — chaque programme compilé et tracé, avec trois exercices corrigés.

💻 MP2I·Informatique

C — Pointeurs et allocation dynamique

Le cœur du C : l'adresse et le pointeur, les opérateurs & et *, pourquoi il faut un pointeur pour modifier une variable (le passage par valeur), le lien tableaux/pointeurs, et malloc/free — chaque programme compilé et tracé, avec trois exercices corrigés.

💻 MP2I·Informatique

OCaml — Premiers pas

Découvrir OCaml, le langage fonctionnel de MP2I : le let et le typage inféré, les fonctions, le piège des opérateurs pointés (+. pour les float), le if/then/else qui renvoie une valeur, et la récursivité let rec (factorielle déroulée) — avec trois exercices corrigés.

💻 MP2I·Informatique

OCaml — Filtrage et listes

Les deux piliers d'OCaml : le filtrage (match ... with) et les listes récursives (:: et []), avec longueur et somme déroulées sur un exemple, les types somme et le type option (Some/None) — attention à l'ordre et à l'exhaustivité des cas, avec trois exercices corrigés.

💻 MP2I·Informatique

C — Structures et listes chaînées

La première structure de données dynamique du programme : les struct, le maillon et l'opérateur flèche p->suivant, l'insertion en tête et le parcours d'une liste chaînée — construction de [3, 5, 8] tracée, avec les pièges (NULL, ordre inversé, fuite mémoire) et trois exercices corrigés.

💻 MP2I·Informatique

C — Piles et files

Les deux structures linéaires fondamentales implémentées en C : la pile (LIFO, empiler/dépiler en tête) et la file (FIFO, avec un pointeur de queue pour enfiler en O(1)) — chaque opération compilée et tracée, avec trois exercices corrigés.

Tu veux aller plus loin sur ce chapitre ?

Nos mentors alumni de Polytechnique, CentraleSupélec et Mines Paris t'accompagnent en cours particuliers — démonstrations détaillées, exos type concours, oraux blancs.

Trouver un mentor →