Author: Christian.Queinnec@lip6.fr

## 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 ;;

1. É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

2. É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

3. É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

4. 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

5. 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

6. 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};;

1. É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>

2. É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

3. É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

4. 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