let incr x =
x := !x + 1
;;
let decr x =
x := !x - 1
;;
let vect_length = Array.length (* En Ocaml `vect` se dit `array `*)
let f1 x =
let y = !x + 1 in
y
;;
let f2 x y =
for i = x to 10 do
y := x :: !y
done;
!y
;;
Mais vous n'avez pas le droit d'utiliser de références de listes sauf indication contraire.
let e3 = if true then "Hello !\n";;
(* Équivalent à *)
let e3 = if true then "Hello !\n" else ();;
(* D'où le problème de type, explicite dans le message d'erreur *)
let e4 = if true then print_string "Bye...\n";;
let e5 =
let x = ref 10; (* erreur ici *)
while !x > 0 do
print_int !x;
print_char ' ';
decr x
done
;;
let e5 =
let x = ref 10 in
while !x > 0 do
print_int !x;
print_char ' ';
decr x
done
;;
let e6 = let x = ref 0 in let y = x in x := !x + 1; y;;
let f7 x y =
if !x > 0 then
decr x;
y := !y + !x
else
incr x
;;
(* Équivalent à *)
let f7 x y =
if !x > 0 then decr x else ();
y := !y + !x
else (* Erreur de syntaxe, que vient faire ce else ?)
incr x
;;
(* Il faut parenthéser pour avoir une version correcte *)
let f7 x y =
if !x > 0 then begin
decr x;
y := !y + !x
end else
incr x
;;
let foo = ref succ;;
let bar x = !foo x;;
bar 2;;
foo := function x -> x + 2;;
bar 2;;
let p = ref 0 in let q = ref p in !(!q) + begin p := 2; !(!q) end;;
Comportement non spécifié ! Ici le membre de droite du +
a été évalué en premier, mais il aurait pû en être autrement (ce n'est pas dans la norme et cela peut dépendre de la machine ou d'une implémentation particulière). Moralité : ne jamais faire cela. Utiliser des let in
pour forcer l'ordre.
let clock = ref 0;;
let time () = incr clock; !clock;;
time ();;
time () + time ();;
(* Comportement non spécifié ! *)
time () - time ();;
let puissance x n =
let res = ref 1 in
for k = 1 to n do
res := x * !res
done;
!res
;;
Il n'y a aucun problème de terminaison. La boucle s'effectue $n$ fois sur un $\Theta(1)$, le reste est en $\Theta(1)$ donc la complexité est linéaire en $n$. Un invariant de boucle est l'égalité entre le contenu de res
et $x^{k - 1}$. Montrons que ceci est bien un invariant et qu'il permet bien de justifier la correction de la fonction :
Initialisation : Il faut se placer juste avant le début de la boucle for
, c'est-à-dire juste après l'initialisation de $k$ qui vaut donc $1$ et juste avant le test qui vérifie si $k$ dépasse $n$. À ce moment là res
a pour contenu $1$ qui est bien égal à $x ^ {1 - 1} = x^0 = 1$.
Transmission : On suppose que l'invariant est vérifié au début de la boucle (pour un certain $k$) et il faut montrer que c'est encore le cas au début de la boucle suivante (donc juste après l'incrémentation de $k$, c'est-à-dire pour $k + 1$). Au début de la boucle, le contenu de res
est donc $x^{k - 1}$. La boucle est constituée d'une seule instruction qui multiplie le contenu de res
par $x$. À la fin de la boucle suivant res
a donc pour valeur $x^{k - 1} \times x = x^k = x^{(k + 1) - 1}$. Au début de la boucle suivante, l'invariant est donc bien vérifié.
Terminaison : la boucle s'arrête lorsque $k$ dépasse $n$, c'est-à-dire lorsque $k = n + 1$. En sortie de boucle on a donc le contenu de res
qui vaut $x ^ {(n + 1) - 1} = x^n$, ce qui est bien le résultat attendu.
let somme_elements tableau =
let n = vect_length tableau in
let somme = ref 0 in
for i = 0 to n - 1 do
somme := !somme + tableau.(i)
done;
!somme
;;
somme_elements [|1; 2; 3; 1; -6|];;
Pour produit_elements
il suffit de remplacer le +
par un *
.
let appartient tableau element =
let n = vect_length tableau in
let trouve = ref false in
let i = ref 0 in
while (not !trouve) && (!i < n) do
trouve := !trouve || (tableau.(!i) = element);
incr i
done;
!trouve
;;
appartient [|2; 1; 4; 2; 3|] 3;;
Lors de chaque passage dans la boucle, la valeur de i
— qui commence à 0 — est incrémentée de 1 ce qui garanti que la condition d'arrêt est atteinte après au plus $n$ passages. Ceci montre que la fonction termine et que sa complexité au pire est en $\Theta(n)$ où $n$ est la taille du tableau puisque tout est en $\Theta(1)$.
Un invariant permettant de prouver la correction : $trouve = element \in tableau[0..i[$. Pour l'initialisation, il est certain que l'élément ne se trouve pas dans le sous-tableau vide $tableau[0,0[$ et $trouve$ est bien faux. La transmission ne pose pas de problème puisque le corps de la boucle revient exactement à affecter à $trouve$ le booléen $element \in tableau[0..i[$ ou $element = tableau[i]$, c'est-à-dire $element \in tableau[0..i + 1[$, suivi d'une incrémentation de $i$, ce qui conserve donc l'invariant. Pour la terminaison, deux conditions de sorties sont possibles. Soit trouvé
est vrai et alors l'élement se situe dans un sous-tableau $tableau[0, i[$ et donc a fortiori dans le tableau (car $i \leq n$), soit trouvé
est faux et alors $i = n$, dans ce cas l'invariant justifie que $element \not\in tableau[0..n[$. Ce qui prouve bien ce que l'on souhaite.
Voir DM n°2.
Voir DM n°2.