Adloun

informatique (MP2I/MPI) · Chapitre 2 · Application directe du cours

Le point-virgule qui sort du then

Le langage OCaml · niveau 2

Énoncé

Cette fonction doit rendre le nombre de termes strictement positifs et leur somme. Sur [| 3; -1; 4; -1; 5 |] elle rend (3, 10) au lieu de (3, 12). Pourquoi, et comment corriger ?


let somme_des_positifs t =
  let positifs = ref 0 and total = ref 0 in
  for i = 0 to Array.length t - 1 do
    if t.(i) > 0 then
      incr positifs;
      total := !total + t.(i)
  done;
  (!positifs, !total)

Corrigé

L'indentation ment. Elle suggère que les deux lignes sont dans le then ; le langage en décide autrement. L'annexe prévient : « les retours à la ligne et l'indentation ne sont pas signifiants ». Le point-virgule sépare deux expressions, et il lie moins fort que le if : le corps de la boucle se lit


(if t.(i) > 0 then incr positifs) ; (total := !total + t.(i))

La somme est donc calculée sur tous les termes : . Le compte, lui, est juste — d'où un résultat à moitié correct, le plus difficile à repérer.

La correction, mesurée :


let somme_des_positifs t =
  let positifs = ref 0 and total = ref 0 in
  for i = 0 to Array.length t - 1 do
    if t.(i) > 0 then begin
      incr positifs;
      total := !total + t.(i)
    end
  done;
  (!positifs, !total)
(* [| 3; -1; 4; -1; 5 |]  donne maintenant (3, 12) = (3, 3 + 4 + 5) *)

begin ... end — ou une paire de parenthèses, strictement équivalente — groupe les deux expressions en une seule, qui devient le then.

Pourquoi le compilateur ne dit rien. Parce que le programme est bien typé : incr positifs a le type unit, et un if sans else de type unit est licite. C'est un des rares endroits où le typage fort ne rattrape rien : il vérifie les types, pas les intentions. La parade est une habitude, pas un outil — on met begin ... end dès que le corps d'un then compte plus d'une expression, même quand ce n'est pas nécessaire.

Exercices semblables

Le cours du chapitre · Tous les exercices du chapitre