Vous êtes sur la page 1sur 4

Abstraction des procédures

L’utilisation de données composées nous permet aussi d’accroître la modularité de nos


programmes. Si nous pouvons manipuler les nombres rationnels directement comme des objets
à part entière, alors nous pouvons séparer la partie de notre programme qui traite des nombres
rationnels eux-mêmes, de la façon dont les nombres rationnels sont représentés par des couples
d’entiers ; La technique générale qui consiste à séparer les parties d’un programme définissant
la représentation des objets-donnée de celle exprimant leurs utilisations est une méthode
puissante de construction appelée abstraction des données.
Nous allons voir comment les abstractions de données rendent les programmes plus faciles à
créer, à mettre à jour et à modifier.
L’utilisation de données composées amène un réel progrès dans le pouvoir d’expression d’un
langage de programmation. Considérons l’idée de former une « combinaison linéaire » ax+by.
Nous aimerions écrire une procédure qui accepterait a, b, x et y comme arguments et
retournerait la valeur de ax+by. Ceci ne présente pas de difficulté si les arguments sont des
nombres parce que nous pouvons immédiatement définir la procédure :
Pour combinaison_linéaire :a :b :x :y
Rends a * x + b * y
Fin
Mais supposons que nous ne nous intéressons pas seulement aux nombres. Nous voudrions, par
exemple, exprimer en termes de procédure, l’idée de former une combinaison linéaire chaque
fois qu’on a défini l’addition et la multiplication _ pour des nombres rationnels, des nombres
complexes ou toute autre chose. Nous pourrions l’exprimer par une procédure de la forme :
Pour combinaison_linéaire :a :b :x :y
Rends add (mult :a :x) (mult :b :y)
Fin
Où add et mult ne sont plus les opérateurs primitifs + et * mais des opérateurs plus complexes
qui réalisent les opérations appropriées sur toutes sortes de données passées en argument a, b,
x et y. Le point fondamental est que la seule chose que combinaison_linéaire doit connaitre sur
a, b, x et y est que les opérateurs add et mult réalisent les opérations appropriées. Du point de
vue de la procédure combinaison_linéaire, peu importe ce que sont a, b, x et y et, moins encore,
peu importe la connaissance de leur représentation en terme de données plus primitives.
On peut concevoir un type de données abstraites comme la connaissance d’un modèle
mathématique et des opérations qui lui sont associées.
Le même exemple montre pourquoi il est important que notre langage de programmation
fournisse la possibilité de manipuler directement des objets composés. Sans cette possibilité,
une procédure comme combinaison_linéaire ne pourrait transmettre ses arguments à add et
mult sans connaitre les détails de leur structure.
La possibilité de manipuler directement des procédures permet d’accroître de la même manière
le pouvoir d’expression d’un langage de programmation.
Nous avons vu que les procédures sont en fait des abstractions décrivant des opérations
composées sur des données.
Par exemple :
Pour Cube :x
Rends x * x * x
Fin
Ne définit pas le cube d’un nombre particulier, mais plutôt une méthode pour obtenir le cube
de n’importe quel nombre. Bien sûr, il est possible de se passer de procédure, en écrivant des
expressions telles que :
3 * 3 * 3
x * x * x
y * y * y
sans jamais mentionner Cube explicitement. Ceci a pour inconvénient de nous contraindre à
toujours travailler au niveau des seules primitives du langage (ici la multiplication) et non avec
des procédures d’ordre supérieur. Nos programmes pourraient calculer des cubes, mais sans
que notre langage sache exprimer l’idée d’évaluation au cube. La capacité de construire des
abstractions en attribuant des noms aux formes courantes est une des choses que l’on doit
attendre d’un langage de programmation puissant, ce qui permet ensuite de travailler
directement avec les abstractions. Les procédures nous donnent cette possibilité. C’est pourquoi
tous les langages de programmation, mis à part les plus primitifs, offrent des mécanismes de
définition de procédures.
Cependant, même dans le domaine du calcul numérique, nous serions sérieusement limités dans
notre capacité de créer des abstractions, si nous étions restreints aux procédures dont les
paramètres doivent être des nombres. Souvent la même structure de programme sera utilisée
par plusieurs procédures différentes. Pour transformer de telles structures en concepts, nous
aurons besoin de construire des procédures qui peuvent prendre d’autres procédures comme
argument ou avoir pour résultat d’autres procédures. Les procédures qui manipulent des
procédures sont appelées des procédures d’ordre supérieur.
Considérons les trois procédures suivantes. La première calcule la somme des entiers de a à b.
Pour Somme_entiers :a :b
Si a>b alors rends 0
Sinon Rends ( :a + Somme_entiers :a + 1 :b)
Fin
La deuxième calcule la somme des cubes des nombres entiers compris dans un intervalle
donné :
Pour Somme_cubes :a :b
Si a>b rends 0
Sinon Rends ((cube :a) + Somme_cubes :a + 1 :b)
Fin

La troisième calcule la somme d’une suite de termes de la série suivante qui converge (très
lentement) vers Π/8 :
1/(1*3) + 1/(5*7) + 1/(9*11) + …
Pour Somme_pi :a :b
Si a>b rends 0
Rends ((1/( :a*( :a+2))) + (Somme_pi :a+4 :b))
Fin
Rq : b étant la borne supérieure de l’intervalle.
Ces trois procédures ont visiblement une structure commune. En grande partie identiques, elles
ne diffèrent que par le nom de procédure, la fonction de a utilisée pour calculer le terme courant
et la fonction qui fournit la valeur suivante de a.
Nous pouvons produire chacune de ces procédures en remplissant les cases d’un même gabarit :
Pour <nom> :a :b
Si a>b rends 0
Sinon Rends (<f> :a + (<nom> (<suivant> :a) :b))
Fin
Cette structure commune met en évidence l’existence d’une abstraction utile sous-jacente.
D’ailleurs, les mathématiciens ont depuis longtemps identifié l’abstraction « somme d’une
série » et inventé la notation « sigma » comme dans :
b
∑ f(n) = f(a) + … + f(b)
n=a
pour exprimer ce concept.
De la même façon, en tant que programmeurs, nous aimerions que notre langage soit assez
puissant pour pouvoir écrire une procédure exprimant l’idée de sommation elle-même et non
pas des procédures calculant des sommes particulières.
Pour Somme :f :a :suivant :b
Si a>b rends 0
Rends ( :f :a + Somme :f ( :suivant :a) :suivant :b)
Fin
Remarquons que Somme a pour arguments les bornes inférieure et supérieure a et b, ainsi que
les procédures f et suivant. Somme s’utilise comme n’importe quelle procédure, par exemple
pour définir Somme_cubes :
Pour Somme_cubes :a :b
Somme :cube :a :suivant :b
Fin
Nous pouvons définir Somme_pi de la même façon :
Pour Somme_pi :a :b
Somme :f_pi :a :suivant_pi :b
Fin
Pour f_pi :x
Rends 1/( :x * ( :x + 2))
Fin
Pour Suivant_pi :x
Rends :x + 4
Fin
Ces procédures nous permettent de calculer une valeur approchée de Π :
8 * Somme_pi 1 1000
Somme peut servir pour bâtir d’autres concepts. Par exemple, la valeur numérique approchée
de l’intégrale définie d’une fonction f entre les bornes a et b se calcule selon la formule :
b
∫ f(x) dx = [ f(a + dx/2) + f(a + dx +dx/2) + f(a + 2dx + dx/2) + …]dx
a
pour de petites valeurs de dx. Ce que nous pouvons exprimer directement dans une procédure :

Pour Intégrale :f :a :b :dx


Rends (Somme :f :a + :dx/2 :add_dx :b) * :dx
Fin
Pour add_dx :x
Rends :dx + :x
Fin

Exemple : Intégrale cube 0 1 0,01


 0,249987492

Conclusion :
Nous avons introduit la procédure Somme qui prend une procédure que nous appellerons terme
comme paramètre et calcule la somme des valeurs de terme sur un intervalle spécifié.
Pour définir Somme, il est très important de pouvoir parler d’une procédure telle que terme
comme d’une entité de plein droit sans lien avec la façon d’exprimer terme par des opérations
plus primitives.

Vous aimerez peut-être aussi