Voir les cours et résoudre les problèmes en :
Le C est un langage de programmation impératif conçu pour la programmation système. Inventé au début des années 1970 avec UNIX, C est devenu un des langages les plus utilisés. De nombreux langages plus modernes se sont inspirés de sa syntaxe. Il privilégie la performance sur la simplicité de la syntaxe. [En savoir plus]
Le C++ est un langage de programmation impératif. Inventé au début des années 1980, il apporte de nouveaux concepts au langage C (les objets, la généricité), le modernise et lui ajoute de nombreuses bibliothèques. C++ est devenu l'un des langages les plus utilisés. Sa performance et sa richesse en font le langage de prédilection pour les concours. [En savoir plus]
Pascal est un langage de programmation impératif inventé dans les années 1970 dans un but d'enseignement. Quoiqu'encore utilisé à cette fin, l'absence de bibliothèque standard en limite son utilisation malgré une grande efficacité. Sa syntaxe a été reprise par d'autres langages plus modernes avec plus ou moins de succès. [En savoir plus]


Remarque : Les cours pour ce langage ne sont disponibles que jusqu'au chapitre 4, « Lecture de l'entrée ». Les corrections sont toutefois toujours fournies.
OCaml est un langage de programmation fonctionnel inventé au milieu des années 1990. Il permet aussi une programmation impérative ou objet. Il permet d'écrire des programmes courts et faciles à vérifier et est ainsi utilisé pour certains systèmes embarqués très sensibles comme ceux des avions. Il est utilisé dans l'enseignement en classes préparatoires aux grandes écoles. [En savoir plus]


Remarque : Les cours pour ce langage ne sont disponibles que jusqu'au chapitre 4, « Lecture de l'entrée ». Les corrections sont toutefois toujours fournies.
Java est un langage de programmation impératif et orienté objet. Inventé au début des années 1990, il reprend en grande partie la syntaxe du langage C++ tout en la simplifiant, au prix d'une performance un peu moins bonne. S'exécutant dans une machine virtuelle, il assure une grande portabilité et ses très nombreuses bibliothèques en font un langage très utilisé. On lui reproche toutefois la « verbosité » de son code. [En savoir plus]


Remarque : Pour un débutant souhaitant apprendre Java, nous conseillons fortement de commencer par JavaScool, plus facile à apprendre, bien que fortement similaire.
Java's Cool (alias JavaScool) est conçu spécifiquement pour l'apprentissage des bases de la programmation. Il reprend en grande partie la syntaxe de Java sur laquelle il s'appuie, mais la simplifie pour un apprentissage plus aisé. La plateforme JavaScool est accompagnée d'un ensemble d'activités diverses de découverte de la programmation. [En savoir plus]
Python est un langage de programmation impératif inventé à la fin des années 1980. Il permet une programmation orientée objet et admet une syntaxe concise et claire qui en font un langage très bien adapté aux débutants. Étant un langage interprété, il n'est cependant pas aussi performant que d'autres langages. [En savoir plus]
Décision

L'expression if expr1 then expr2 else expr3expr1 est une expression de type bool, et où les expressions expr2 et expr3 sont forcément de même type, constitue une structure décisionnelle. Lorsque la condition expr1 vaut true, la structure est équivalente à expr2, et dans le cas contraire lorsque expr1 vaut false, la structure est équivalente à expr3.

D'abord dans le cas où expr2 et expr3 sont de type unit :

let x = read_int() in
if x >= 0
  then print_string "positif"
  else print_string "négatif"

Ici, la condition est x >= 0. Les expressions print_string "positif" et print_string "négatif" sont toutes les deux de type unit.

Lorsque les expressions expr2 ou expr3 sont construites comme juxtapositions de plusieurs expressions, il faut délimiter le bloc. Cela se fait de préférence avec begin et end, bien qu'on puisse aussi utiliser des parenthèses en théorie.

Voici l'exemple précédent dans lequel on a rajouté l'affichage de la valeur absolue du nombre lorsque celui-ci est négatif :

let x = read_int() in
if x >= 0 then
  print_string "positif"
else
  begin
  print_string "négatif, de valeur absolue : ";
  print_int (abs x)
  end

Maintenant dans le cas où expr2 et expr3 ne sont pas de type unit : ces deux expressions doivent être de même type, et ce type est alors celui de l'ensemble de la structure if.

Par exemple, lorsque x est défini, l'expression :

if x >= 0 then "positif" else "négatif"

est de type string, puisque "positif" et "négatif" sont tous les deux de type string.

Ainsi :

let x = read_int() in
print_string (if x >= 0 then "positif" else "négatif");

affiche le signe de l'entier x donné par l'utilisateur.

On peut aussi associé un nom à l'expression formée par la structure if :

let x = read_int() in
let signe = if x >= 0 then "positif" else "négatif" in
print_string signe

Dans ce cas, il sera préférable de présenter cela sur plusieurs lignes, comme on présente les fonctions :

let x = read_int() in
let signe =
  if x >= 0
     then "positif"
     else "négatif"
  in
print_string signe

Voyons un cas où expr2 et expr3 où sont des juxtapositions d'expressions, d'un autre type que unit. En fait on l'a déjà utilisé, pour le jeu ``C'est plus, c'est moins'' en récursif :

if cible > essai then
  begin
  print_string "C'est plus\n";
  succ (cible jeu)
  end
else if cible < essai then
  begin
  print_string "C'est moins\n";
  succ (cible jeu)
  end
else
  begin
  print_string "C'est gagné !\n";
  1
  end
;

Terminons avec le bloc du else implicite.

L'expression if expr1 then expr2 est équivalente à if expr1 then expr2 else (). Par conséquent, expr1 doit être de type bool et expr2 doit être de type unit.

Par exemple :

let x = read_int() in
if x > 0
  then print_string "positif"

est équivalent à

let x = read_int() in
if x > 0
  then print_string "positif"
  else ()

Si expr2 n'est pas de type unit, cela provoque une erreur de type. Illustration :

let x = read_int() in
print_string (if x > 0 then "positif")
File "test.ml", line 2, characters 28-37:
This expression has type string but is here used with type unit

Erreur sur la chaîne "positif" qui n'est pas de type unit.

Calcul booléen

Le ET du calcul booléen, opérateur &&, est en fait équivalent à une structure avec des if. Cherchons l'équivalent de expr1 && expr2. Si expr1 est vrai, alors si expr2 est aussi vrai, le résultat est vrai. Mais si expr1 ou expr2 est faux, le résultat est faux. Ceci s'écrit :

if expr1 then
  begin
  if expr2
     then true
     else false
  end
else
  false

Mais l'expression if expr2 then true else false est équivalente à la valeur de expr2 directement. Donc en simplifiant le code et la présentation, il reste :

if expr1
  then expr2
  else false
Conclusion :

L'expression expr1 && expr2 où les deux expr1 et expr2 sont de type bool est équivalente à if expr1 then expr2 else false.

Il y a une observation importante à faire : si expr1 est évalué à faux, alors expr2 ne sera même pas évalué, puisqu'on est déjà sûr que le résultat de expr1 && expr2 est faux.

Pour vérifier cela, on va utiliser des expressions qui affichent quelque chose lorsqu'elles sont évaluées. Pour commencer, on va ainsi prendre pour expr1 l'expression print_string "expr1 "; true et pour expr2 l'expression print_string "expr2 "; true, et voir ce qu'il se passe en affichant le résultat de expr1 && expr2 :

let b = (print_string "expr1 "; true) && (print_string "expr2 "; true) in
print_string (string_of_bool b);
Ce code affiche expr1 expr2 vrai. On en déduit que expr1 a été évalué, puis expr2, et que expr1 && expr2 était vrai.

Regardons maintenant ce qu'il se passe si on fait que expr2 soit faux :

let b = (print_string "expr1 "; false) && (print_string "expr2 "; true) in
print_string (string_of_bool b);
Ce code affiche cette fois expr1 faux. On en déduit que expr1 a été évalué, mais pas expr2, et que le résultat de expr1 && expr2 était faux.

On va calquer le raisonnement effectué pour le ET pour traiter le OU. L'expression expr1 || expr2 vaut vrai lorsque l'une ou l'autre des deux expressions est vraie. Traduisons cela avec des if. Si expr1 est vrai, on est sûr que le résultat est vrai. Sinon il faut regarder si expr2 est vrai ou faux.

On a donc :
if expr1 then
  true
else
  begin
  if expr2
     then true
     else false
  end
qui se simplifie tout de suite en :
if expr1
  then true
  else expr2
Conclusion :

L'expression expr1 || expr2 où les deux expr1 et expr2 sont de type bool est équivalente à if expr1 then true else expr2.

Vous pouvez vérifier que lorsque la condition expr1 est vrai, la condition expr2 n'est même pas évaluée.

Boucles
La structure :
for compteur = expr1 to expr2 do
  expr3
done
  • compteur est le nom du compteur,
  • expr1 et expr2 sont des entiers, valeurs initiale et finale.
  • expr3 est une expression de type unit où l'on peut utiliser le nom du compteur, le corps de la boucle,

forme une expression de type unit, qui se comporte comme la répétition de expr3 pour toutes les valeurs de compteur comprises entre expr1 et expr2 inclus. S'il n'existe pas de telle valeur pour le compteur, alors la boucle ne fait rien et est équivalente à ().

Remarque : les valeurs initiales et finales du compteur, expr1 et expr2, ne sont évaluées qu'une seule fois au début. La preuve :

for i = (print_string "expr1 "; 1) to (print_string "expr2 "; 5) do
  print_int i;
done;

affiche expr1 expr2 12345.

On a également la règle suivante.

La structure :
while expr1 do
  expr2
done

expr1 (la condition de la boucle) est de type bool et expr2 (le corps de la boucle) de type unit est une expression de type unit, qui se comporte comme la répétition de expr2 tant que l'expression expr1 est évaluée à vrai.

Par exemple :
let i = ref 1 in
while (print_string "expr1 "; !i <= 5) do
  print_int !i;
  incr i;
done;

affiche "expr1 1 expr1 2 expr1 3 expr1 4 expr1 5 expr1". Ainsi l'expression expr1 qui détermine l'exécution de la boucle est exécuté tout au début, mais aussi tout à la fin : la fois où elle est évaluée à faux.

Fonctions

La définition d'une fonction :

let arg_de_la_fonction arg_1 arg_2 ... arg_N =
  expr1 in

arg_de_la_fonction et tous les arg_i sont des noms, forme une expression de type :

type(arg_1) -> type(arg_2) -> ... -> type(arg_N) -> type(expr_1)

les types des arguments étant déduits de l'utilisation qui en est faîte dans expr1.

L'expression :

nom_de_fonction expr_1 expr_2 ... expr_N

lorsque nom_de_fonction est associé à une fonction de type

type_arg_1 -> type_arg_2 -> ... -> type_arg_N -> type_retour

est une expression de type type_retour, à condition que chaque expr_i soit de type type_arg_i.

Pensez à vous inscrire pour valider les cours et résoudre les exercices.