next up previous contents index
Next: Chapitre 4 Up: Programmes en Caml Previous: Chapitre 2

Chapitre 3

Remarque: nous suivons les signatures des procédures C. Les listes étant polymorphes et prédéfinies en Caml, on les utilise plus naturellement sans déclarer un type liste particulier. La manipulation des listes est facilitée en Caml par la gestion automatique de la mémoire: allocation et libération sont implicites. Enfin les listes prédéfinies ne sont pas mutables.

type element == int;;

type liste = Nil | Cons of cellule

and cellule =
{ mutable contenu : element;
  mutable suivant : liste };;

(* {\em Ajouter, voir page \pageref{prog:ajouter-liste}} *)
let lajouter x ap =
 ap := Cons {contenu = x; suivant = !ap};;
lajouter :
 element -> liste ref -> unit = <fun>

(* {\em Recherche, voir page \pageref{prog:recherche-liste}} *)
let lrecherche x a =
 let l = ref a in
 let result = ref false in
 while !l <> Nil do
  match !l with
  | Cons {contenu = y; suivant = s} ->
     if x = y then result := true
     else l := s
  | _ -> ()
 done;
 !result;;
lrecherche : element -> liste -> bool = <fun>

(* {\em Longueur d'une liste, voir page \pageref{prog:longueur-liste-rec}} *)
let rec llongueur = function
| Nil -> 0
| Cons {suivant = reste; _} ->
    1 + llongueur reste;;

(* {\em Longueur d'une liste, voir page \pageref{prog:longueur-liste}} *)
let llongueur a =
 let r = ref 0
 and accu = ref a in
 while !accu <> Nil do
  incr r;
  match !l with
  | Cons {suivant = reste; _} ->
     accu := reste
  | _ -> ()
 done;
 !r;;

(* {\em Supprimer, voir page \pageref{prog:supprimer-liste-recursif}} *)
let lsupprimer x ap =
 let rec supprime precedente = function
 | Nil -> ()
 | Cons ({contenu = c; suivant = reste}
         as cellule) ->
    if c = x then precedente.suivant <- reste
    else supprime cellule reste in
 match !ap with
 | Nil -> ()
 | Cons ({contenu = c; suivant = reste}
          as cellule) ->
    if c = x then ap := reste
    else supprime cellule reste;;

(* {\em Liste des nombres premiers, voir page \pageref{prog:liste-premiers}} *)
let liste_premier n =
 let a = ref Nil in
 for i = n downto 2 do lajouter i a done;
 let k = ref 2 in
 let b = ref !a in
 while !k * !k <= n do
  match !b with
  | Nil -> failwith "liste_premier"
  | Cons {contenu = c; suivant = s} ->
     k := c;
     for j = c to n / c do
      lsupprimer (j * !k) a done;
     b := s
 done;
 a;;

(* {\em Les files avec des vecteurs, voir page \pageref{prog:files-vect}} *)
let maxf = 100;;

type 'a file =
{ mutable debut: int;
  mutable fin: int;
  mutable pleine: bool;
  mutable vide: bool;
  contenu: 'a vect };;

let fairefvide () = {debut = 0; fin = 0;
     pleine = false; vide = true; 
     contenu = make_vect maxf 0};;

let successeur x = (x + 1) mod maxf ;;

let fvide f = f.vide;;

let fpleine f = f.pleine;;

let fvaleur f = begin
  if f.vide then failwith "Pile vide.";
  f.contenu.(f.debut)
  end;;

let fajouter x f = begin
  if f.pleine then failwith "Pile pleine.";
  f.contenu.(f.fin) <- x;
  f.fin <- successeur (f.fin);
  f.vide <- false;
  f.pleine <- f.fin = f.debut;
  end;;

let fsupprimer f = begin
  if f.vide then failwith "File vide.";
  f.debut <- successeur (f.debut);
  f.vide <-  f.fin = f.debut;
  f.pleine <- false;
  end;;


(* {\em Les files avec des listes, voir page \pageref{prog:files-listes}} *)

type 'a liste = Nil | Cons of 'a cellule
and 'a cellule =
 {contenu: 'a; mutable suivant: 'a liste};;

type 'a file =
{ mutable debut: 'a cellule;
  mutable fin: 'a cellule };;

let fairefvide f =
 let b =
  {contenu = f.debut.contenu;
   suivant = Nil} in
 f.debut <- b; f.fin <- f.debut;;

let successeur c = c.suivant;;

let fvide f = f.fin == f.debut;;

let fvaleur f =
 match successeur f.debut with
 | Nil -> failwith "Pile vide"
 | Cons cell -> cell.contenu;;

let fajouter x f =
 let b = {contenu = x; suivant = Nil} in
 f.fin.suivant <- Cons b;
 f.fin <- b;;

let fsupprimer f =
 match successeur f.debut with
 | Nil -> ()
 | Cons cell -> f.debut <- cell;;


(* {\em Déclarations et opérations sur les piles,}
   {\em voir page \pageref{prog:piles}} *)

type 'a pile =
{mutable hauteur: int;
 mutable contenu: 'a vect};;

let fairepvide p = p.hauteur <- 0;;

let pvide p = p.hauteur = 0;;

let pajouter x p =
 p.contenu.(p.hauteur) <- x;
 p.hauteur <- p.hauteur + 1;;

let pvaleur p =
 let i = p.hauteur - 1 in
 p.contenu.(i);;

let psupprimer p = p.hauteur <- p.hauteur - 1;;

(* {\em Opérations sur les piles, version plus traditionelle} *)

type 'a pile == 'a list ref;;

let fairepvide () = ref  [];;

let pvide p = (!p = []);;

let pajouter x p = p := x :: !p;;

let pvaleur p = match !p with
    [] -> failwith "Pile Vide."
  | x :: p' -> x;;

let psupprimer p =  p := match !p with
    [] -> failwith "Pile Vide."
  | x :: p' -> p';;

(* Evaluation des expressions préfixées,
   {\em voir page \pageref{prog:evaluation-prefixe}} *)
type expression == element vect
and element =
| Symbole of char
| Nombre of int;;

let calculer a x y =
 match a with
 | `+` -> x + y
 | `*` -> x * y
 | _ -> failwith "unknown operator";;

let rec inserer x p =
 match x with
 | Symbole c -> pajouter x p
 | Nombre n ->
    if pvide p then pajouter x p else
    match pvaleur p with
    | Symbole c as y -> pajouter x p
    | Nombre m ->
       psupprimer p;
       match pvaleur p with
       | Symbole c ->
         psupprimer p;
         let res = Nombre (calculer c n m) in
         inserer res p
       | _ -> failwith "pile mal construite";;

let evaluer u =
 let p =
   {hauteur = 0;
    contenu = make_vect 100 (Nombre 0)} in
 for i = 0 to vect_length u - 1 do
  match u.(i) with
  | Nombre _ | Symbole `+`
  | Symbole `*` as x -> inserer x p
  | _ -> ()
 done;
 match pvaleur p with
 | Symbole c -> failwith "pile mal construite"
 | Nombre n -> n;;

let pile_of_string s =
 let u =
  make_vect (string_length s) (Symbole ` `) in
 let l = ref 0 in
 for i = 0 to string_length s - 1 do
  let element =
    match s.[i] with
    | `0` .. `9` as c ->
       let n =
        int_of_char c - int_of_char `0` in
       begin match u.(!l) with
       | Symbole c -> Nombre n
       | Nombre m ->
          decr l; Nombre (10 * m + n)
       end
    | c -> Symbole c in
  incr l;
  u.(!l) <- element
 done;
 sub_vect u 0 !l;;

evaluer
 (pile_of_string
   "(* (+ 10 (* 2 3)) (+ (* 10 10) (* 9 9)))");;
- : int = 1996



(* {\em Tail et cons, voir page \pageref{prog:tail}} *)
let tail = function
| Nil -> failwith "tail"
| Cons cell -> cell.contenu;;

let cons x l =
 Cons {contenu = x; suivant = l};;

(* Append et nconc,
   {\em voir page \pageref{prog:append}} *)
let rec append a b =
  match a with
  | Nil -> b
  | Cons cell ->
     cons (cell.contenu)
          (append cell.suivant b);;

let nconc ap b =
 match !ap with
 | Nil -> ap := b
 | _ ->
    let c = ref !ap in
    while
     match !c with
     | Cons {suivant = (Cons cell as l); _} ->
         c := l; true
     | _ -> false
    do () done;
    match  !c with
     | Cons cell -> cell.suivant <- b
     | _ -> ();;

(* Plus conforme au style Caml:
   on utilise une fonction récursive locale,
   on fait l'opération physique sur la liste,
   mais on rend un résultat *)
let rec nconc a b =
 let rec nconc_aux c =
  match c with
  | Nil -> b
  | Cons ({suivant = Nil; _} as cell) ->
      cell.suivant <- b; a
  | Cons {suivant = l; _} -> nconc_aux l in
 nconc_aux a;;

(* Nreverse et reverse,
   {\em voir page \pageref{prog:reverse}} *)
let nreverse ap =
 let a = ref !ap in
 let b = ref Nil in
 let c = ref Nil in
 while
   match !a with
   | Nil -> false
   | Cons ({suivant = s; _} as cell) ->
      c := s;
      cell.suivant <- !b;
      b := !a;
      a := !c;
      true
 do () done;
 ap := !b;;

(* Version plus habituelle:
   on renverse la liste en place
   et l'on rend la nouvelle tête de liste *)
let nreverse l =
 let rec nreverse_aux a b =
  match a with
  | Nil -> b
  | Cons ({suivant = s; _} as cell) ->
     cell.suivant <- b;
     nreverse_aux s a in
  nreverse_aux l Nil;;

let rec reverse a =
   match a with
   | Nil -> a
   | Cons cell ->
      append (reverse cell.suivant)
             (cons (cell.contenu) Nil);;

(* {\em Insert, voir page \pageref{prog:insert}} *)
let insert v l =
 match l with
 | Nil -> failwith "insert"
 | Cons c ->
    let rec insert_aux a =
     match a with
     | Nil -> failwith "insert"
     | Cons cell ->
        if v > cell.contenu && cell != c
        then insert_aux cell.suivant
        else cell.suivant <-
               cons v cell.suivant in
    insert_aux c.suivant;
    c.contenu <- l.contenu + 1;;



1/11/1998