Exercices
 Classes et modules pour structures de données
On désire construire des hiérarchies de classes à partir de 
l'application de foncteurs
pour des structures de données classiques.
On définit les signatures suivantes : 
# module type ELEMENT = 
   sig
     class element : 
        string ->
        object  
          method to_string : unit -> string 
          method of_string : string -> unit 
        end
   end ;;
# module type STRUCTURE = 
   sig
     class ['a] structure : 
       object 
         method add : 'a -> unit
         method del : 'a -> unit
         method mem : 'a -> bool
         method get : unit -> 'a 
         method all : unit -> 'a list         
         method iter : ('a -> unit) -> unit
       end
   end ;;
- 
 Écrire un module à 2 paramètres 
M1 et M2 de types ELEMENT et STRUCTURE, 
construisant une sous-classe de ['a] structure dont le
'a est contraint à M1.element.
 
# module Struct_Elmt (E:ELEMENT) (S:STRUCTURE) = 
   struct
     class e_structure = 
       object
         inherit [E.element] S.structure 
        end
   end ;;
module Struct_Elmt :
  functor(E : ELEMENT) ->
    functor(S : STRUCTURE) ->
      sig
        class e_structure :
          object
            method add : E.element -> unit
            method all : unit -> E.element list
            method del : E.element -> unit
            method get : unit -> E.element
            method iter : (E.element -> unit) -> unit
            method mem : E.element -> bool
          end
      end
 -  Écrire un module simple Entier  
respectant la signature ELEMENT.
 
# module Entier : ELEMENT = 
   struct 
     class element v = 
       object 
         val mutable n = int_of_string v  
         method to_string () = string_of_int n 
         method of_string x = n <- (int_of_string x)
       end
   end ;;
module Entier : ELEMENT
 -  Écrire un module simple Pile  
respectant la signature de STRUCTURE. 
 
# module Pile : STRUCTURE =
   struct
     class ['a] structure = 
       object
         val mutable p = ( [] : 'a list )
         method add x = p <- x::p 
         method del x = p <- List.filter ((<>) x) p
         method mem x = List.mem x p 
         method get () = List.hd p
         method all () = p
         method iter f = List.iter f p 
       end
   end ;;
module Pile : STRUCTURE
 -  Appliquer le foncteur à ces deux 
paramètres.
 
# module Pile_Entier = Struct_Elmt(Entier)(Pile) ;;
module Pile_Entier :
  sig
    class e_structure :
      object
        method add : Entier.element -> unit
        method all : unit -> Entier.element list
        method del : Entier.element -> unit
        method get : unit -> Entier.element
        method iter : (Entier.element -> unit) -> unit
        method mem : Entier.element -> bool
      end
  end
 -  Modifier le foncteur initial en ajoutant 
les méthodes to_string et of_string.
 
# let split c s = 
   let suffix s i = 
     try  String.sub s i ((String.length s)-i) 
     with Invalid_argument("String.sub") -> "" 
   in
   let rec split_from n = 
     try  let p = String.index_from s n c 
          in (String.sub s n (p-n)) :: (split_from (p+1)) 
     with Not_found -> [ suffix s n ] 
   in 
   if s="" then [] else split_from 0 ;;
val split : char -> string -> string list = <fun>
# module Elmt_Struct (E:ELEMENT) (S:STRUCTURE) = 
   struct
     class element v = 
       object (self)
         val n = new S.structure 
         method to_string () = 
           let res = ref "" in 
           let f x = res := !res ^ ((x#to_string ())  ^ " ") in 
           n#iter f ;
           !res 
         method of_string x = 
           let l = split ' ' x in 
           List.iter (fun x -> n#add (new E.element x)) l
         initializer self#of_string v  
       end
   end ;;
module Elmt_Struct :
  functor(E : ELEMENT) ->
    functor(S : STRUCTURE) ->
      sig
        class element :
          string ->
          object
            val n : E.element S.structure
            method of_string : string -> unit
            method to_string : unit -> string
          end
      end
 -  Appliquer le foncteur de nouveau, puis 
l'appliquer au résultat.  
 
 
# module Entier_Pile = Elmt_Struct (Entier) (Pile) ;;
module Entier_Pile :
  sig
    class element :
      string ->
      object
        val n : Entier.element Pile.structure
        method of_string : string -> unit
        method to_string : unit -> string
      end
  end
 
# module Entier_Pile_Pile =  Elmt_Struct (Entier_Pile) (Pile) ;;
module Entier_Pile_Pile :
  sig
    class element :
      string ->
      object
        val n : Entier_Pile.element Pile.structure
        method of_string : string -> unit
        method to_string : unit -> string
      end
  end
 Types abstraits
En reprenant l'exercice précédent, on cherche à implanter un module de signature 
ELEMENT dont la classe element utilise une variable d'instance
d'un type abstrait. 
On définit le type paramétré suivant : 
# type 'a t = {mutable x : 'a t; f : 'a t -> unit};;
- 
 Écrire les fonctions apply, 
from_string et to_string. Ces deux dernières
fonctions utilisent le module Marshal. 
 
# let apply val_abs = val_abs.f val_abs.x ;;
val apply : 'a t -> unit = <fun>
# let from_string s = Marshal.from_string s 0 ;;
val from_string : string -> 'a = <fun>
# let to_string v = Marshal.to_string v [Marshal.Closures] ;;
val to_string : 'a -> string = <fun>
 -  Écrire une signature S correspondant 
à la signature inférée précédemment en abstrayant le type t.
 
# module type S = 
   sig 
     type t
     val apply : t -> unit
     val from_string : string -> t
     val to_string : t -> string 
   end ;;
module type S =
  sig
    type t
    val apply : t -> unit
    val from_string : string -> t
    val to_string : t -> string
  end
 -  Écrire un foncteur qui prend un paramètre 
de signature S et retourne un module dont la signature est
compatible avec ELEMENT. 
 
# module Element_of (M:S) = 
   struct 
     class element v = 
       object   
         val mutable n = M.from_string v
         method to_string () = M.to_string n 
         method of_string x = n <- M.from_string x 
       end
   end ;;
module Element_of :
  functor(M : S) ->
    sig
      class element :
        string ->
        object
          val mutable n : M.t
          method of_string : string -> unit
          method to_string : unit -> string
        end
    end
 -  Utiliser le module résultat comme paramètre 
du module de l'exercice précédent. 
 
# module Abstrait_Pile (M:S) =  Elmt_Struct (Element_of(M)) ;;
module Abstrait_Pile :
  functor(M : S) ->
    functor(S : STRUCTURE) ->
      sig
        class element :
          string ->
          object
            val n : Element_of(M).element S.structure
            method of_string : string -> unit
            method to_string : unit -> string
          end
      end