Précédent Index Suivant

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

Précédent Index Suivant