contrainte de type par signature

This commit is contained in:
gwen 2017-10-12 18:21:33 +02:00 committed by Benjamin Bohard
parent 98dd6eea17
commit 07b57d4515
2 changed files with 241 additions and 38 deletions

View File

@ -37,8 +37,8 @@ def setup(app):
app.add_config_value('correction', False, 'env')
app.add_config_value('exercice', False, 'env')
exercice = False
correction = False
exercice = True
correction = True
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View File

@ -7,17 +7,28 @@ définies.
Ces modules doivent être aussi indépendants que possible.
module
.. glossary::
ensemble de ressources les sémantiquement
module
interface
ensemble de ressources liées sémantiquement
mode demploi du module, avec en plus un principe de masquage
des informations (partie publique, partie secrète)
interface
mode demploi du module, avec en plus un principe de masquage
des informations (partie publique, partie secrète)
Signatures, type abstrait et langage de modules : la programmation modulaire
signature
suite de déclarations, types, exceptions, valeurs, modules, etc.
implantation
suite de définitions, qui doit comporter tout ce qui est requis par la
signature
Type abstrait et langage de modules : la programmation modulaire
permet d'aller très loin dans la programmation structurée.
@ -188,7 +199,7 @@ Le langages des modules
(* implémentation du module *)
module Pile : PILE = (* le module est restreint
par la signature PILE *)
par la signature PILE *)
struct
type a t = a list ref
let create () = ref []
@ -216,41 +227,41 @@ En dehors du module, on accède à ses composants grâce à la notation pointée
let p = Pile.create()
Pile.push 45 p
Les foncteurs
--------------
Si un langage possède un langage de modules, on peut aller plus loin : on peut
considérer un module comme étant une expression de base du langage.
- La signature d'un module peut être considérée comme le type du module
- La structure du module peut être considéré comme sa valeur
Quel est l'intérêt ? On peut alors définir des **foncteurs**.
foncteur
"fonction" d'une structure vers une autre structure.
On peut ainsi paramétrer un module par un autre module.
.. code-block:: ocaml
module Nom (M1 :S1 ) (M2 :S2 ) (M3 :S3 ) ... =
struct
...
end
On applique un foncteur à des paramètres modules, pour
obtenir un nouveau module :
.. code-block:: ocaml
module M = F (Titi) (Toto)
**Signature inférée** : Lorsque la déclaration d'interface n'existe pas.
Contrainte de type par signature
------------------------------------
::
.. code-block:: ocaml
module M =
struct
type t = int * int * int
let make d m y = d,m,y
end
module M :
sig type t = int * int * int
val make : a -> b -> c -> a * b * c end
.. ifconfig:: exercice
ici la signature inférée est du type le plus général.
Cela peut poser des difficultés. Lesquelles ?
.. ifconfig:: correction
une incohérence entre type attendu et type obtenu
.. code-block:: ocaml
# let d = M.make 52 24 137 ;;
val d : int * int * int = (52, 24, 137)
.. code-block:: ocaml
module M =
struct
@ -270,6 +281,58 @@ Contrainte de type par signature
MS.make 5 1 2 ;;
autre exemple
.. code-block:: ocaml
module type DATE =
sig
type t = int * int * int
val mmax : int -> int -> int
val make : int -> int -> int -> t
val get_day : t -> int
val get_month : t -> int
val get_year : t -> int
end
on est alors obligé de contrôler la vraissemblance des valeurs dans chaque fonction du module, sinon le contrôle n'est pas maîtrisé...
.. code-block:: ocaml
M.get_month (23,45,67);;
- : int = 45
Le problème vient du fait que limplantation du type Date.t est **publique**.
Le Type abstrait de données permet de masquer limplantation du type.
.. code-block:: ocaml
module type DATE = sig
type t
val mmax : int -> int -> int
val make : int -> int -> int -> t
val get_day : t -> int
val get_month : t -> int
val get_year : t -> int
end
usage::
# module Date = (M:DATE) ;;
module Date : DATE
Le contrôle est maîtrisé::
Date.get_month (23,45,67);;
This expression has type int * int * int but is here used with type Date.t
Si (M:S) alors la structure M est une instance de la signa-
ture S
Type et signature
------------------
@ -311,3 +374,143 @@ Module auquel on impose une signature
end ;;
module date = (MR:DATE) ;;
Structure et signature
-----------------------
Une structure peut avoir plusieurs signatures
.. code-block:: ocaml
# module Cpt =
struct
let x = ref 0
let reset () = x := 0
let next () = incr x; !x
end
.. ifconfig:: exercice
Créer deux modules nayant pas les mêmes droits sans toucher à
limplantation.
.. ifconfig:: correction
une vue administrateur
.. code-block:: ocaml
module type ADM =
sig
val reset : unit -> unit
val next : unit -> int
end
::
module Adm = (Cpt:ADM)
# (* le compteur lui-même est invisible *)
# Adm.x;;
Unbound value Adm.x
une vue utilisateur
.. code-block:: ocaml
module type USR =
sig
val next : unit -> int
end
::
# module Usr = (Cpt:USR)
# Usr.next();;
- : int = 1
# Usr.reset();;
Unbound value Usr.reset
Contrainte partage du code (et du compteur) : impossible de construire deux composants administrateurs et utilisateurs autonomes.
- une unité qui contient les trois modules
- un composant qui publie les deux modules mais pas le module commun (un package)
L'héritage par inclusion
------------------------
.. code-block:: ocaml
# module Cpt2 = struct
include Cpt
let get() = !x
let next() = x := 2 * !x; !x
end ;;
module Cpt2 :
sig
val x : int ref
val reset : unit -> unit
val get : unit -> int
val next : unit -> int
end
Les foncteurs
--------------
Si un langage possède un langage de modules, on peut aller plus loin : on peut
considérer un module comme étant une expression de base du langage.
- La signature d'un module peut être considérée comme le type du module
- La structure du module peut être considéré comme sa valeur
Quel est l'intérêt ? On peut alors définir des **foncteurs**.
foncteur
"fonction" d'une structure vers une autre structure.
On peut ainsi paramétrer un module par un autre module.
.. code-block:: ocaml
module Nom (M1 :S1 ) (M2 :S2 ) (M3 :S3 ) ... =
struct
...
end
On applique un foncteur à des paramètres modules, pour
obtenir un nouveau module :
.. code-block:: ocaml
module M = F (Titi) (Toto)
exemple, le module Set::
module OrderedInt =
struct type t=int let compare = compare end ;;
module OrderedInt : sig type t = int val compare : a -> a -> int end
# module IntSet = Set.Make(OrderedInt)
module IntSet :
sig
type elt = OrderedInt.t
type t = Set.Make(OrderedInt).t
val empty : t
Ou, plus court::
module IntSet = Set.Make(struct type t=int let compare = compare end)
Le parallèle peut se faire entre les classes et les modules.
- module : Encapsulation données/traitements
- classes : différenciation données/traitements et possibilité de création de plusieurs instances
classes et types, inférences de types de classes