(* Cours numero 4: les aspets imperatifs et le systeme de modules*)


(* les exceptions *)




(* un type somme ouvert *)


exception Liste_zero;;

let multlist_eff l = 
  let rec aux = function [] -> 1
                |    (a::r) -> if a=0 then raise Liste_zero
                                      else a*(aux r)
  in try aux l with Liste_zero -> 0;;

(* vecteurs *)


let v = [|"a"|];;

(* acces de 0 a n-1 *)


v.(0);;

(* affectation *)


v.(0)<- "aa";;

v.(0);;

(* enregistrements avec champs modifiables *)


type point = {mutable x:int};;

let movepoint p dx = p.x<-p.x+dx;;

(* les cases memoire *)


type 'a ref = {mutable info: 'a};;

let refval {info=v} = v;;
let setref v r = r.info<-v;;

(* ce type predefini pour comodite, avec !r pour refval r et r:=v pour setref v r *)


(* un neud d'une liste avec "pointeurs" explicites *)


type 'a cell = {info: 'a; mutable next: 'a cell};;

(* exemple: liste circulaires *)




(* on utilise les noeuds ... *)


let make_cl v = let rec c = {info=v;next=c} 
                in c;;

let hd {info=v;next=l} = l.info;;

let tl {next=rest} = rest;;

let insert_hd v cl = let el = {info=v;next=cl.next}
                     in cl.next<-el; cl;;

let insert_tl v cl = let el = {info=v;next=cl.next}
                     in cl.next<-el; el;;

let remove_hd cl = cl.next<- cl.next.next; cl;;

(* mais cela ne marche que sur le liste non vides: *)




(* on va faire mieux ... *)


type 'a circ_list = Nil | List of 'a cell;;

(* il nous faut traiter les cas exceptionnels: *)




(* on definit des exceptions aussi *)


let insert_head v = function Nil -> List (make_cl v)
                    | (List cl)  -> List (insert_hd v cl);;

let insert_tail v = function Nil -> List (make_cl v)
                    | List cl    -> List (insert_tl v cl);;

exception Remove_Empty_cl;;

let remove_head   = function Nil -> raise Remove_Empty_cl
                    | List cl    -> let v =hd cl
                                    in let l= if cl.next==cl.next.next then Nil
                                              else List (remove_hd cl)
                                       in (v,l);;

(* cela est suffisant pour definir un type de donnee pile avec *)




(* insertion et suppression en temps constant *)



( Les Modules )

( terminologie de l'algebre: les modules sont comme des algebres: )

( ils ont une sig(nature), sont des struc(tures), et on les transforme )

( avec des foncteurs )

module type File = sig exception FileVide type 'a file val mkempty: unit -> 'a file val enqueue: 'a -> 'a file -> 'a file val dequeue: 'a file -> 'a * 'a file val isempty: 'a file -> bool end;;

module FileCLPasProtege = struct type 'a cell = {info: 'a; mutable next: 'a cell} let make_cl v = let rec c = {info=v;next=c} in c

let hd {info=v;next=l} = l.info

let insert_tl v cl = let el = {info=v;next=cl.next} in cl.next<-el; el

let remove_hd cl = cl.next<- cl.next.next; cl

type 'a circ_list = Nil | List of 'a cell

let insert_tail v = function Nil -> List (make_cl v) | List cl -> List (insert_tl v cl)

exception Remove_Empty_cl

let remove_head = function Nil -> raise Remove_Empty_cl | List cl -> let v =hd cl in let l= if cl.next==cl.next.next then Nil else List (remove_hd cl) in (v,l)

( attention aux pieges avec les effets de bord: si on ecrit )

( (hd cl, if .. then .. else ... remove_hd cl ..) )

( il peut arriver que remove_hd soit execute avant hd!!! )

exception FileVide type 'a file = 'a circ_list let mkempty () = Nil let enqueue v l = insert_tail v l let dequeue l = try remove_head l with Remove_Empty_cl -> raise FileVide let isempty = function Nil -> true | _ -> false end;;

( si on veut faire propre, on peut restraindre la signature )

module FileCL = (FileCLPasProtege : File);;

FileCL.enqueue;;

( Une autre structure de file: meme cout amortit, mais fonctionnelle )

module FileDL : File = struct type 'a file = 'a list * 'a list exception FileVide let mkempty () = [],[] let enqueue v (l1,l2) = (l1,v::l2) let dequeue = function (a::r,l) -> a,(r,l) | ([], []) -> raise FileVide | ([], l) -> let (a::l') = List.rev l in (a,(l',[])) let isempty = function ([],[]) -> true | _ -> false end;;

type 'a arbre = Empty | Node of 'a arbre * 'a * 'a arbre

module ParcLarg = functor (F:File) -> struct let rec bf f p = if F.isempty f then List.rev p else let (a,f') = F.dequeue f in match a with Empty -> bf f' p | Node(g,v,d) -> bf (F.enqueue d (F.enqueue g f')) (v::p) let parclarg a = bf (F.enqueue a (F.mkempty())) [] end;;

let b= Node (Node (Node (Empty, 4, Empty), 2, Node (Empty, 5, Empty)), 1, Node (Node (Empty, 6, Empty), 3, Node (Empty, 7, Empty)));;

( et maintenant, testons le tout! )

module PCL = ParcLarg(FileCL);; PCL.parclarg b;; module PDL = ParcLarg(FileDL);; PDL.parclarg b;;