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