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]
Type d'une fonction

Chaque valeur est d'un certain type. Par exemple 5 est un int, "super" est de type string, et ref 3 est de type int ref. Pour les fonctions, c'est pareil, chacune d'elle va avoir un type. Ce type dépendra de deux choses : d'une part des types des paramètres que la fonction prend, et d'autre part du type de valeur que la fonction retourne. Lorsque la fonction ne retourne rien, on utilisera par convention le mot "unit" pour traduire cette absence de valeur. Voyons tout de suite une série d'exemples.

La fonction absolue :

let absolue x =
  if x >= 0
     then x
     else -x
  in

prend en paramètre un entier, et renvoie un entier. Le type d'une telle fonction s'écrit par convention de la manière suivante : ce qu'elle prend en paramètre, flèche vers la droite, ce qu'elle donne. C'est pourquoi le type de absolue est " int -> int ", ce qui se lit ``int donne int''.

Une petite astuce permet de vérifier que c'est bien le type int -> int qui a été déduit par le compilateur pour la fonction absolue. L'idée est de faire exprès d'afficher une erreur de typage, de manière à obtenir un message du genre "this expression has type ... but is here used with type ...". Essayons par exemple l'instruction print_int absolue, qui est absurde puisqu'une fonction n'est pas un entier, et ne peut donc sûrement pas être affiché avec print_int.

let absolue x =
  if x >= 0
     then x
     else -x
  in
print_int absolue;
File "test.ml", line 6, characters 10-17:
This expression has type int -> int but is here used with type int

L'expression ligne 6 entre les caractères 10 et 17 est le nom de la fonction absolue. Comme prévu, cette expression est de type int donne int. On a ici essayé d'utiliser print_int dessus, qui attend un int, et on a donc obtenu une erreur de type.

La règle de typage est exactement la même pour les fonctions qui réalisent des actions avant de renvoyer une valeur :

let somme_entiers n =
  let total = ref 0 in
  for i = 1 to n do
     total := !total + i;
  done;
  !total in

est aussi de type " int -> int".

Reprenons maintenant la fonction affiche_ligne :

let affiche_ligne motif =
  for colonne = 1 to nb_colonnes do
     print_string motif;
  done;
  in

Cette fonction prend en paramètre une chaîne, nommée motif, et ne renvoie rien : elle se

contente de faire quelque chose. On a dit que dans ce cas on utilisait le type "unit". Donc le type de la fonction affiche_ligne est : " string -> unit ".

Le type "unit" sert également dans le cas des fonctions qui n'ont pas de paramètres. Ne pas avoir de paramètres est considéré comme avoir un paramètre de type unit. Tout simplement :

let separation () =
  print_newline();
  print_string "- - - - -";
  print_newline();
  in

est de type " unit -> unit ".

La fonction recup_somme :

let recup_somme () =
  let x = read_int() in
  let y = read_int() in
  x + y in

est elle de type " unit -> int ".

Dernier point, les fonctions à plusieurs paramètres : on met les type des paramètres les uns à la suite des autres, séparés par des flèches, que l'on lit toujours "donne". Et on indique toujours le type de la valeur de retour à la fin. Ainsi :

let moyenne a b =
  (a +. b) /. 2.0 in

est de type " float -> float -> float ".

Autre exemple :

let affiche_ligne_motif nb_colonnes motif =
  for colonne = 1 to nb_colonnes do
     print_string motif;
  done;
  print_newline();
  in

est de type " int -> string -> unit ".

Remarque : il n'y a jamais qu'une seule valeur de retour pour une fonction. Si on veut vraiment retourner plusieurs valeurs d'un coup, il faudra les regrouper dans une structure, et cette structure sera alors considérée comme une seule valeur. Mais on n'étudiera pas cela tout de suite.

Exercices

Quels sont les types des fonctions prédéfinies qui suivent ?

print_newline
print_int
print_float
print_string
read_int
read_float
read_line

Écrivez-les avant de lire les réponses qui sont données ci-dessous.

Par convention, on écrit le type d'une valeur après le nom de la valeur suivi d'un deux-points.

print_newline : unit -> unit
print_int : int -> unit
print_float : float -> unit
print_string : string -> unit
read_int : unit -> int
read_float : unit -> float
read_line : unit -> string

Quels sont les types de ces autres fonctions prédéfinies :

abs           (* valeur absolue d'un entier *)
pred          (* prédécesseur d'un entier *)
abs_float     (* valeur absolue d'un réel *)
sqrt          (* racine carrée d'un réel *)
cos           (* cosinus d'un réel *)
float_of_int  (* réel à partir d'un entier *)
int_of_float  (* entier à partir d'un réel *)

Écrivez-les avant de lire les réponses qui sont données ci-dessous.

abs : int -> int
pred : int -> int
abs_float : float -> float
sqrt : float -> float
cos : float -> float
float_of_int : int -> float
int_of_float : float -> int
Polymorphisme

Certaines fonctions ont des types un peu particuliers. C'est le cas de la fonction maximum, qui a la propriété de fonctionner aussi bien avec des paramètres int que des paramètres float :

let maximum x y =
  if x > y
     then x
     else y
  in

En regardant l'erreur que nous donnerait une instruction "print_int maximum;", on apprend que la fonction maximum a pour type :

'a -> 'a -> 'a

Le symbole 'a veut dire : "un type donné". Le type de cette fonction traduit le fait que la fonction doit prendre deux arguments du même type, pour qu'une comparaison puisse être effectuée, et renvoie une valeur du même type que les arguments. Ainsi maximum peut être vue comme une une fonction de type int -> int -> int ou float -> float -> float, mais ne peut pas être vue comme du int -> float -> float, par exemple.

On aura l'occasion de reparler de cette propriété d'utilisation de types indéterminés plus tard. On verra que c'est un aspect très puissant de Caml. Pour l'instant, il faut juste savoir que ça existe pour ne pas être dérouté par certains messages d'erreurs.

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