IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours complet d’initiation à la programmation


précédentsommairesuivant

Chapitre 4 – Constantes et variables

4-1. Types de données

En programmation, les données manipulées peuvent être de natures différentes : nombres entiers, nombres réels, chaînes de caractères, booléens… Ces différentes natures de données sont appelées types de données.

Le langage Caml dispose d'un certain nombre de types prédéfinis.

4-1-1. Les booléens

Le type bool est le type des expressions booléennes permettant d'écrire les conditions des instructions if et while. Les données de ce type ne peuvent prendre que deux valeurs.

Nom : bool
Ensemble des valeurs : true, false
Littéraux : true et false
Opérateurs : &&, || , not

Exemple 1 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
# true;;
- : bool = true
# not(true);;
- : bool = false
# true || false;;
- : bool = true

4-1-2. Les nombres entiers

Le type int est le type des expressions numériques entières.

Nom : int
Ensemble des valeurs : le type int est limité aux entiers appartenant à un intervalle [[emin,emax]], et il y a donc un plus petit et un plus grand entier. Cet intervalle dépend de l'architecture du processeur de l'ordinateur utilisé. Sur des architectures 32 bits, on a

[[emin, emax]] = [[-230 , 230 - 1]] = [[−1 073 741 824, 1 073 741 823]].

Sur des architectures 64 bits, on a

[[emin, emax]] = [[-262, 262 - 1]] = [[−4 611 686 018 427 387 904, 4 611 686 018 427 387 903]].

Littéraux : les entiers dans leur forme écrite usuelle. Par exemple : 24.
Constantes prédéfinies : les constantes min_int et max_int donnent les valeurs du plus petit (emin) et du plus grand (emax) entier.
Opérateurs arithmétiques : +, -, *, /, mod
Opérateurs de comparaison : =, <>, <, <=, >, >=

Remarque : Les calculs arithmétiques sur les nombres de type int s'effectuent modulo emax - emin + 1.

Exemple 2 :

La session ci-dessous est effectuée sur une machine 32 bits.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
# (1+2) *3;;
- : int = 9
# 9 / 2;;
- : int = 4
# 9 mod 5;;
- : int = 4
# max_int;;
- : int = 1073741823
# min_int;;
- : int = -1073741824
# max_int + 1;;
- : int = -1073741824
# min_int - 1;;
- : int = 1073741823

4-1-3. Les nombres flottants

Les nombres flottants sont définis avec le mot clé  : float

4-1-4. Types définis par le module Cartes

Le module Cartes définit deux types couleur et numero_tas(11).

Nom : couleur.
Ensemble des valeurs : Les données de ce type ne peuvent prendre que quatre valeurs notées : CARREAU, TREFLE, PIQUE et COEUR.
Nom : numero_tas.
Ensemble des valeurs : Les données de ce type ne peuvent prendre que quatre valeurs : 1, 2, 3 et 4.

4-2. Variables

4-2-1. Notion de variable

Les variables servent à nommer des valeurs.

Elles sont caractérisées par leur nom ou identificateur, leur type et leur valeur.

4-2-2. Déclaration simple de variables

La déclaration des variables se fait à l'aide du mot réservé (ou mot-clé) let.

Syntaxe : Déclaration d'une variable
Sélectionnez
1.
let < identificateur > = < expression >

<identificateur> est le nom de la variable, et <expression> l'expression qui définit sa valeur.

Exemple 3 :

Voici la déclaration d'une variable nommée a, de type int et de valeur 12.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
# let a = 12;;
val a : int = 12
# a;;
- : int = 12
# 2 * a;;
- : int = 24

L'expression qui définit la valeur d'une variable peut faire référence à d'autres variables à condition que celles-ci aient été préalablement déclarées.

Exemple 4 :

À la suite de la déclaration de la variable a qui précède, on peut déclarer une nouvelle variable b comme ci-dessous

 
Sélectionnez
1.
2.
# let b = 2*a + 1;;
val b : int = 25

4-2-3. Identificateurs de variables

Les variables sont nommées par un identificateur. En Caml, les identificateurs de variables doivent obligatoirement commencer par une lettre minuscule ou un blanc souligné (_) et peuvent être complétés par n'importe quelle quantité de lettres minuscules ou majuscules non accentuées, ou chiffres, ou blancs soulignés.

Exemple 5 :

Le tableau ci-dessous montre quelques exemples d'identificateurs de variables corrects et incorrects.

Identificateurs corrects

Identificateurs incorrects

a

A

a1

1a

a_b

a-b

_a

-a

deplacer_sommet

deplacer-sommet

En plus de ces règles, certains mots ne peuvent pas être utilisés comme identificateurs : ce sont les mots réservés ou mots-clés du langage (cf annexe C.2C.2 Mots-clés du langage).

4-2-4. Environnement

L'ensemble des variables définies dans un contexte de calcul s'appelle un environnement.

Lorsque l’on déclare une variable, on augmente l'environnement courant de cette nouvelle variable. Ainsi, si dans un certain environnement E0 on déclare la variable

 
Sélectionnez
1.
2.
# let a = 12 ;;
val a : int = 12

l'environnement qui suit cette déclaration est augmenté d'une variable nommée a et de valeur 12, et l'environnement est maintenant

E1 =< a, 12 >: E0.

Après la déclaration

 
Sélectionnez
1.
2.
# let b = 5 ;;
val b : int = 5

l'environnement est

E2 = < b, 5 >: E1 = < b, 5 >:< a, 12 >: E0.

On voit donc que la déclaration de variables peut augmenter l'environnement. Mais rien ne peut faire diminuer l'environnement : une variable déclarée le reste pour toute la durée de la session.

4-2-5. Évaluation d'une expression

Lorsqu'une expression contient une ou plusieurs variables, pour chacune de ces variables on cherche dans l'environnement courant la variable de même nom la plus récemment déclarée, et on la remplace par la valeur correspondante.

Par exemple dans l'environnement E2 précédemment décrit, l'expression a*b est transformée en 12*5 qui finalement donne la valeur 60.

a∗b ⇒ 12∗5 ⇒ 60.

4-2-6. Masquage d'une variable

Nous l'avons vu un environnement ne peut qu'augmenter. Que se passe-t-il lorsque nous déclarons une variable dont le nom est identique à celui d'une variable déjà déclarée ? Que se passe-t-il si l’on déclare une nouvelle variable nommée a dans l'environnement E2 ?

Et bien, rien de neuf. Une nouvelle variable est ajoutée à l'environnement. Par exemple, si dans l'environnement E2 on fait la déclaration

 
Sélectionnez
1.
2.
# let a = 9 ;;
val a : int = 9

l'environnement devient

E3 = < a, 9 >: E2 = < a, 9 >:< b, 5 >:< a, 12 >: E0.

On constate que l'environnement E2 contient deux variables de même nom a : l'une valant 12 qui dans le temps a été la première à être déclarée, l'autre valant 9 qui est la plus récente.

Quelle est alors la valeur de l'expression a*b dans l'environnement E3 ? Dans l'expression, on remplace la variable b par sa valeur 5, mais qu'en est-il pour a ? 9 ou 12 ? La règle d'évaluation dit de choisir la valeur de la variable la plus récemment déclarée, autrement dit 9. Par conséquent, dans l'environnement E3 l'expression a*b vaut 45.

a∗b ⇒ 9∗5 ⇒ 45.

Dans l'environnement E3, toute référence à la variable a est une référence à la variable < a, 9 >. L'autre variable < a, 12 > est masquée par < a, 9 >.

4-2-7. Déclaration simultanée de variables

Plusieurs variables peuvent être définies simultanément dans la même phrase let en utilisant le mot-clé and.

Syntaxe : Déclaration simultanée de plusieurs variables
Sélectionnez
1.
2.
3.
4.
let < identificateur 1 > = < expression 1 >
and < identificateur 2 > = < expression 2 >
...
and < identificateur n > = < expression n >

Les expressions <expressioni> sont alors toutes évaluées dans l'environnement dans lequel la phrase de déclaration est exprimée.

Exemple 6 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
# let a = 1
  and b = 2;;
val a : int = 1
val b : int = 2
# a + b ;;
- : int = 3

La déclaration simultanée de plusieurs variables n'est pas équivalente à la déclaration séquentielle. Par exemple, on peut tout à fait effectuer les deux déclarations successives suivantes

 
Sélectionnez
1.
2.
3.
4.
# let c = 1. ;;
val c : float = 1.
# let d = c +. 2. ;;
val d : float = 3.

mais il n'est pas possible de demander la déclaration simultanée qui suit si aucune déclaration préalable d'une variable e de type float n'a été faite.

 
Sélectionnez
1.
2.
3.
# let e = 1.
  and f = e +. 2. ;;
Unbound value e

En effet dans l'environnement d'évaluation de cette déclaration, la variable e n'existe pas, et il n'est donc pas possible d'évaluer l'expression e +. 2..

Mais si une déclaration préalable a été faite il n'y a aucun problème.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
# let e = -3.;;
val e : float = -3.
# let e = 1.
  and f = e +. 2. ;;
val e : float = 1.
val f : float = -1.

À noter que dans l'environnement obtenu après ces déclarations, la variable e vaut 1., et f vaut -1., autrement dit f a été calculée avec la valeur de e dans l'environnement précédent.

4-2-8. Variables locales à une expression

Nous l'avons vu, l'environnement courant des variables déclarées ne peut que croître. Cela peut poser deux problèmes :

  • un accroissement inutile de l'environnement avec des variables qui ne servent pas, et qui peut provoquer un encombrement, voire une saturation de la mémoire ;
  • un masquage de certaines variables lorsqu'on utilise un même nom.

Bien souvent, on éprouve le besoin de déclarer une variable pour faciliter l'écriture d'une expression et/ou optimiser son évaluation.

Par exemple, si nous souhaitons calculer l'expression

kitxmlcodelatexdvp\sqrt{a^2+b^2} \times \frac{1+\sqrt{a^2+b^2}}{2+\sqrt{a^2+b^2}}finkitxmlcodelatexdvp

on pourrait écrire (en supposant que dans l'environnement courant il y ait deux variables a et b de valeurs flottantes)

 
Sélectionnez
1.
2.
3.
sqrt(a**2. +. b**2.) *.
  (1. +. sqrt(a**2. +. b**2.)) /.
  (2. +. sqrt(a**2. +. b**2.))

mais cela n'est évidemment pas satisfaisant parce que d'une part l'expression n'est pas facilement lisible, et d'autre part dans son évaluation, la sous-expression kitxmlcodeinlinelatexdvp\sqrt{a^2+b^2}finkitxmlcodeinlinelatexdvp va être calculée trois fois.

Pour mener des calculs, il arrive souvent que, pour ne pas noyer le propos par de longues formules, on utilise des notations pour les simplifier. On « pose » que tel symbole vaut temporairement telle valeur, et ensuite on utilise ce symbole en lieu et place de celle-ci.

Sur notre exemple cela pourrait donner : soit kitxmlcodeinlinelatexdvp\alpha = \sqrt{a^2+b^2}finkitxmlcodeinlinelatexdvp dans l'expression

kitxmlcodelatexdvp\alpha \times \frac{1+\alpha}{2+\alpha}finkitxmlcodelatexdvp

dont une traduction possible en Objective Caml est

 
Sélectionnez
1.
2.
let alpha = sqrt(a**2. +. b**2.)
alpha *. (1. +. alpha) /. (2. +. alpha)

Cette façon de mener le calcul remédie aux deux défauts signalés ci-dessus :

  • le code est beaucoup plus lisible ;
  • la sous-expression kitxmlcodeinlinelatexdvp\sqrt{a^2+b^2}finkitxmlcodeinlinelatexdvp n'est calculée qu'une seule fois, et donc on gagne en efficacité.

Cependant, en procédant de la sorte on a introduit dans l'environnement courant une nouvelle variable dont l'intérêt est limité au seul calcul de notre expression. Par la suite la variable kitxmlcodeinlinelatexdvp\alphafinkitxmlcodeinlinelatexdvp ne sera probablement plus utilisée mais persistera dans l'environnement : c'est une pollution.

Il existe une solution pour éviter la pollution de l'environnement par des variables d'intérêt temporaire : c'est la notion de variable locale à une expression.

Ce qui manque dans notre exemple c'est la traduction de « posons kitxmlcodeinlinelatexdvp\alpha = \dotsfinkitxmlcodeinlinelatexdvp dans l'expression… ». Il ne faut pas déclarer une variable, puis calculer une expression, mais déclarer une variable à utiliser dans une expression. En Objective Caml, cela se traduit avec la forme letin. Notre exemple devient alors

 
Sélectionnez
1.
2.
3.
let alpha = sqrt(a**2. +. b**2.)
in
  alpha *. (1. +. alpha) /. (2. +. alpha)

Avec une telle déclaration, la variable alpha ne vient s'ajouter à l'environnement courant que pour la durée de l'évaluation de l'expression qui suit. Sitôt cette évaluation terminée, elle est supprimée, et n'existe donc pas dans l'environnement courant à l'issue du calcul. Il n'y a aucune différence entre l'environnement avant et après évaluation. Le problème de pollution d'environnement est réglé.

La syntaxe générale de déclaration de variables locales est donnée ci-dessous.

Syntaxe : Déclaration de variables locales à une expression
Sélectionnez
1.
2.
3.
4.
5.
let < identificateur 1 > = < expression 1 >
and < identificateur 2 > = < expression 2 >
...
in
  < expression >

Les variables non locales déclarées par une simple forme let sont appelées variables globales par opposition à locales.

4-2-9. Remarque sur la forme let

En Objective Caml, la forme let n'est pas une expression et a fortiori n'est pas une instruction.

Utilisée dans une séquence d'instructions elle ne donne pas l'effet auquel on pourrait penser. Dans la séquence qui suit

 
Sélectionnez
1.
2.
3.
4.
# let a = 1 ;
  a + 1;;
Warning S: this expression should have type unit.
Unbound value a

on constate un avertissement sur le fait que la première partie n'a pas le type unit, et un message d'erreur montre que dans l'environnement courant la variable a n'est liée à aucune valeur, et ceci malgré la forme de la déclaration qui précède.

Utilisée dans une expression conditionnelle, elle provoque un message d'erreur de syntaxe.

 
Sélectionnez
1.
2.
3.
4.
5.
# if true then begin
    let a = 1;
    print_string ("Fini")
  end ;;
Syntax error

De même dans les instructions répétées (boucle while ou for).

En conclusion, une déclaration globale de variable ne peut être encapsulée dans une séquence d'instructions, dans une expression conditionnelle ou dans une boucle.

En revanche, la forme letin est une expression. À ce titre elle peut être encapsulée.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
# let a = 1 in print_int a ;
  print_newline () ;;
1
- : unit = ()
# if true then begin
    let a = 1 in
      print_int (a+1)
  end ;;
2- : unit = ()

4-3. Variables mutables

4-3-1. Motivation

Un problème

  • État initial : Tas 1 un nombre quelconque de cartes, les autres tas sont vides.
  • État final : peu importe.
  • But : afficher le nombre de cartes situées initialement sur le tas 1.

Algorithme

Une solution du problème consiste à déplacer (une à une) toutes les cartes du tas 1 vers un autre tas (le tas 2 par exemple), et à compter chaque déplacement effectué.

Algorithme 4.1 Compter les cartes du tas 1

mise à zéro du compteur
tant que le tas 1 n'est pas vide faire
    déplacer une carte du tas 1 vers le tas 2
    ajouter 1 au compteur
fin tant que

Comme on peut le voir, dans cet algorithme la valeur du compteur évolue durant son exécution.

Une variable dont la valeur peut évoluer durant l'exécution d'un programme est appelée variable mutable. Par opposition, nous nommerons parfois les variables non mutables des constantes.

4-3-2. Déclaration d'une variable mutable

La déclaration d'une variable mutable est analogue à celle de toute variable, si ce n'est l'emploi du mot-clé ref.

Syntaxe : Déclaration d'une variable mutable
Sélectionnez
1.
let < identificateur > = ref < expression >

Exemple 7 :

Déclaration d'une variable mutable compteur initialisée à 0.

 
Sélectionnez
1.
2.
# let compteur = ref 0 ;;
val compteur : int ref = {contents = 0}

Comme on peut le voir, cette variable n'est pas de type int, mais de type int ref. Et sa valeur est {contents = 0}.

 
Sélectionnez
1.
2.
# compteur ;;
- : int ref = {contents = 0}

Comme compteur n'est pas de type int, on ne peut pas l'utiliser tel quel dans le contexte d'une expression où l’on attend un int.

 
Sélectionnez
1.
2.
# compteur + 1;;
This expression has type int ref but is here used with type

4-3-3. Référence à la valeur d'une variable mutable

Pour faire référence à la valeur d'une variable mutable dans une expression, on utilise le préfixe ! devant le nom de la variable.

Exemple 8 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
# !compteur ;;
- : int = 0
# !compteur + 1;;
- : int = 1
# !compteur;;
- : int = 0

Notez qu'après l'évaluation de la deuxième expression, la variable compteur a gardé la valeur 0.

Pour modifier la valeur d'une variable mutable, il faut utiliser l'instruction d'affectation.

4-3-4. Affectation

L'affectation est une instruction qui permet de changer la valeur d'une variable mutable.

La syntaxe de cette instruction est

Syntaxe : Affectation d'une valeur à une variable mutable
Sélectionnez
1.
< identificateur > := < expression >

Le symbole := signifie que la valeur v de l'expression < expression > est affectée à la variable désignée par l'identificateur < identificateur >. Après l'exécution de cette instruction la variable < identificateur > vaut v.

Comme toute instruction, le résultat d'une affectation est la valeur () de type unit.

Exemples :

  1. Pour mettre à zéro la variable compteur précédemment déclarée ;

     
    Sélectionnez
    1.
    2.
    3.
    (* compteur = xxx *)
    compteur := 0 ;
    (* compteur = 0 *)
    
  2. Ajouter 1 au compteur ;

     
    Sélectionnez
    1.
    2.
    3.
    (* compteur = n *)
    compteur := !compteur + 1 ;
    (* compteur = n + 1 *)
    

Remarques :

  1. Attention à ne pas confondre le symbole := utilisé en Caml pour l'instruction d'affectation, avec le symbole = utilisé comme opérateur de comparaison, ainsi que dans la déclaration de variables.
  2. En programmation, on est souvent amené à utiliser des instructions du type

     
    Sélectionnez
    1.
    a := !a + 1
    

    qui augmentent de 1 la valeur d'une variable (mutable). Cette opération s'appelle incrémentation et on dit qu'on incrémente une variable.

    La décrémentation est la diminution de la valeur d'une variable.

     
    Sélectionnez
    1.
    a := !a - 1
    
  3. On peut penser que le code suivant est équivalent à une incrémentation.

     
    Sélectionnez
    1.
    let a = a+1
    

    Il n'en est rien du tout ! Il s'agit d'une déclaration d'une nouvelle variable a qui vient masquer la précédente. De plus, on ne peut pas utiliser cette forme let dans une boucle.

    Par exemple, on peut écrire

     
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    10.
    11.
    12.
    13.
    # let a = ref 0 ;;
    val a : int ref = {contents = 0}
    # while !a < 5 do
        a := !a + 1;
        print_int !a;
        print_newline ()
      done ;;
    1
    2
    3
    4
    5
    - : unit = ()
    

    mais on ne peut pas écrire

     
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    # let a = 0 ;;
    val a : int ref = {contents = 0}
    # while a < 5 do
        let a = a + 1;
        print_int (a);
        print_newline () )
      done ;;
    Syntax error
    
  4. L'affectation est une opération autorisée sur les variables mutables uniquement. Elle ne l'est pas sur les variables non mutables (ou constantes).

     
    Sélectionnez
    1.
    2.
    3.
    4.
    # let a = 1 ;;
    val a : int = 1
    # a := 2;;
    This expression has type int but is here used with type 'a ref
    

4-4. Afficher des données

En Caml, lorsqu'on veut afficher des données, on utilise les instructions print_int pour les entiers, print_float pour les flottants.

Exemple 9 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
# print_int(1234);;
1234- : unit = ()
# let a = 1234;;
val a : int = 1234
# print_int(a*2);;
2468- : unit = ()
# print_int(1234.);;
This expression has type float but is here used with type int
# print_float(1234.);;
1234.- : unit = ()

Comme on peut le voir ces instructions impriment la valeur du paramètre sans passer à la ligne. Cela peut poser problème lorsqu'on veut afficher deux nombres successifs.

Exemple 10 :

 
Sélectionnez
1.
2.
3.
4.
5.
# begin
  print_int(1);
  print_int(2)
end ;;
12- : unit = ()

L'instruction sans paramètre print_newline provoque un passage à la ligne.

Exemple 11 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
# begin
  print_int(1);
  print_newline();
  print_int(2);
  print_newline()
end ;;
1
2
- : unit = ()

L'instruction print_string imprime une chaîne de caractères.

Exemple 12 :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
# let a = 12
  and b = 21
  in
  begin
    print_int(a);
    print_string(" + ");
    print_int(b);
    print_string(" = ");
    print_int(a+b);
    print_newline()
  end ;;
12 + 21 = 33
- : unit = ()

4-5. Le programme solution du problème 4.3.1

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
(* compter le nombre de cartes sur le tas 1 *)
let cpt = ref 0
in
begin
  init_tas(1,"[T]");
  init_tas(2,"");
  init_tas(3,"");
  init_tas(4,"");
  while tas_non_vide(1) do
    deplacersommet(1,2);
    cpt := !cpt + 1
  done;
  print_string("Nombre de cartes initialement sur le tas 1 : ");
  print_int(!cpt);
  print_newline()
end

4-6. Exercices

Exercice 4-1 Déclarations de variables

Décrivez les valeurs des variables déclarées à l'issue des deux sessions suivantes :

 
Sélectionnez
1.
2.
3.
let a = 1 ;;
let a = 2 ;;
let b = 2*a + 1 ;;
 
Sélectionnez
1.
2.
3.
let a = 1 ;;
let a = 2
and b = 2*a + 1 ;;

Exercice 4-2 Échange de variables

Donnez une séquence d'instructions qui échange les valeurs de deux variables mutables de type int.

Exercice 4-3 Calcul de la valeur d'une fonction polynomiale

Soit kitxmlcodeinlinelatexdvpf(x) =x^4 - 3x^3 - 2x^2 + x + 1finkitxmlcodeinlinelatexdvp

Réalisez un programme qui affiche la valeur de kitxmlcodeinlinelatexdvpf(x)finkitxmlcodeinlinelatexdvp lorsque kitxmlcodeinlinelatexdvpx = 13finkitxmlcodeinlinelatexdvp. Concevez votre programme pour qu'il soit facile de le modifier pour le calcul de kitxmlcodeinlinelatexdvpf(x)finkitxmlcodeinlinelatexdvp pour d'autres valeurs de kitxmlcodeinlinelatexdvpxfinkitxmlcodeinlinelatexdvp.

Cette dernière solution suit le schéma de Horner d'évaluation d'un polynôme.

Exercice 4-4 Avec les cartes

Réalisez des programmes qui, à partir de la situation initiale

Situation initiale :

Tas 1 : "[K+T+P+C]" Tas 2 : ""

Tas 3 : "" Tas 4 : ""

  1. calcule le nombre de trèfles ;
  2. calcule le nombre de cartes de couleur noire ;
  3. répartit équitablement les cartes rouges sur les tas 3 et 4, et les cartes noires sur les tas 1 et 2.

précédentsommairesuivant
Le nom complet de ces types est en fait Cartes.couleur et Cartes.numero_tas. Dans le texte du poly nous n'employons que la notation raccourcie.

Licence Creative Commons
Le contenu de cet article est rédigé par Université Lille1 et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Pas de Modification 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2019 Developpez.com.