Une légende dit que c’est alité par une maladie, que Descartes aurait eu l’idée d’associer les points du plan à des couples de nombres. Voici ce qu’en écrit Cauchy, en 1823 :

La notion de couple, même avant d’être formalisée, est donc omniprésente en mathématiques, notamment en géométrie repérée et en analyse, faisant intervenir des couples (x,y). Un graphe orienté est un ensemble de couples (inclus dans le produit cartésien) donc cette notion est fondamentale, puisque les relations (en particulier les fonctions) sont des graphes orientés.
Voici comment le couple (a,b) est modélisé dans la théorie des ensembles de Tarski et Grothendieck :

La construction des entiers naturels par Von Neumann n’est pas si naturelle que ça (celle des numéraux de Church non plus). La modélisation des couples en théorie des ensembles souffre du même problème, et il semble préférable de considérer la notion de couple comme une notion primitive. La notion est abordable intuitivement dès le milieu de cycle 2, en notant a→b le couple (a,b). C’est la notation avec les parenthèses qui est moins intuitive.
D’autres modélisations ont été proposées depuis plus d’un siècle.

Emballages
Il n’y a pas que pour construire un couple en théorie des ensembles, que l’idée d’emballer dans plusieurs couches un (ou plusieurs) objet mathématique, s’est révélée fructueuse. On va voir ici, comme un bonus à cet article, trois exemples d’utilisation en informatique :
- Les monades en Haskell
- Les décorations de fonctions en Python.
- Le sucre syntaxique des langages de programmation
monades
Un exemple archétypal de foncteur est la fonction map de Python. Par exemple, à partir de la catégorie des réels, map transforme une fonction R→R en une fonction (N→R)→(N→R) (à une liste L1 de réels, elle associe une liste de réels). Ce genre de foncteur, en Haskell, s’appelle une monade :
Une monade est un foncteur M assorti de deux fonctions
- unit (ou return) de type a → M a
- join de type M M a → M a
En, bref, la monade M permet d’emballer a dans un paquet cadeau M a, sans qu’il y ait besoin de suremballer, puisqu’une deuxième couche peut être réduite (par join) à une seule.
La construction des ensembles peut être faite en programmation fonctionnelle, par cette monade :
à ces deux objets a et b | unit associe ces deux ensembles |
![]() |
![]() |
Dans ce cas la jointure est la réunion ensembliste (à un ensemble d’ensembles elle associe leur réunion).
Une monade sert donc à emballer ou empaqueter une fonction (en Haskell tous les objets sont des fonctions). On parle d’encapsulation.
On peut se demander à quoi ça sert, en Haskell, d’emballer une fonction dans un paquet cadeau. En fait, les monades sont très utilisées pour gérer les effets de bord chers à Dana Scott, en ajoutant quelque chose (le contexte, des variables globales ou l’environnement) dans le paquet. Les monades les plus importantes sont IO (entrées-sortie) et State (état de la machine). Elles sont similaires au itérateurs de Python, qui à chaque appel, gardent mémoire de l’état de l’itération. Mais en Python, enrober une fonction avec une variable globale, se fait par un décorateur.
décorateurs
En Python, ce sont les fonctions que l’on décore. En fait il ne s’agit pas que d’emballer la fonction dans du papier cadeau, mais plutôt de la transformer (par des ajouts).
Pour voir à quoi cela peut servir de modifier une fonction après l’avoir définie, on va prendre pour exemple un problème qui se pose chaque fois que l’on veut représenter graphiquement une fonction prenant de grandes valeurs. Par exemple l’hyperbole représentant la fonction inverse est difficile à afficher avec matplotlib.pyplot :
Pour pouvoir représenter graphiquement une fonction qui n’est pas définie en 0, on s’arrange pour remplacer 0 par une valeur proche mais possédant un inverse. La fonction représentée graphiquement est donc définie ainsi :
def inverse(x):
if x==0:
x = 1e-6
return 1/x
Comme on a approché 0 par 10-6, la première ordonnée est 1000000 et on ne voit pas bien l’hyperbole. Pour résoudre ce problème, on propose de limiter les ordonnées (par exemple en leur imposant d’être comprises entre -1 et 1). La fonction faisant cela est une fonctionnelle (fonction dont la valeur d’entrée et la valeur renvoyée sont elles-mêmes des fonctions), que voici :
def limiter(f):
def fL(x):
if -1<=f(x)<=1:
return f(x)
elif f(x)<-1:
return -1
else:
return 1
return fL
La valeur d’entrée f est donc la fonction à limiter, pour ce faire on définit une fonction fL (fonction limitée) dépendant de la variable x∈R et qui coïncide avec f(x) si x est entre -1 et 1, avec -1 ou 1 sinon. La fonctionnelle limiter modifie la fonction f selon cet algorithme :
- elle définit une fonction locale fL, qui est la version limitée de f (les valeurs renvoyées sont entre -1 et 1) ;
- elle renvoie cette fonction ;
- pour en faire un décorateur, il reste à remplacer la fonction non limitée, par la fonction limitée.
Pour mieux voir l’hyperbole, il suffit maintenant de précéder la définition de la fonction inverse, d’un appel à la limiter :
@limiter
def inverse(x):
if x==0:
x = 1e-6
return 1/x
Cette seule ligne ajoutée avant la définition de la fonction donne une hyperbole bien mieux visible :
On peut se demander à quoi cela sert de décorer une fonction, plutôt que de la modifier directement. L’intérêt essentiel des décorateurs est qu’ils peuvent servir plusieurs fois.
sucre
Le sucre syntaxique s’applique à un langage de programmation. L’expression s’inspire du fondant (pâtisserie) :
- D’une part on enrobe le langage (on lui rajoute des choses sans rien lui enlever).
- D’autre part le résultat a un goût agréable (sucré) : le nouveau langage (enrichi) est plus naturel.
Par exemple CoffeeScript est décrit comme du sucre syntaxique sur JavaScript. Ce qui signifie que pour obtenir la fonction Javascript suivante :
var sinus;
sinus = function(x) {
return sin(x / pi * 180);
};
on entre simplement ceci dans l’interpréteur CoffeeScript :
sinus = (x) -> sin x/pi*180
C’est plus court et plus proche de la langue naturelle. Ce que l’on résume par l’expression sucre syntaxique.
Commentaires