diff --git a/algo/AlgoApprofondie/cours/conf.py b/algo/AlgoApprofondie/cours/conf.py index 3005e97..f1939b9 100644 --- a/algo/AlgoApprofondie/cours/conf.py +++ b/algo/AlgoApprofondie/cours/conf.py @@ -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'] diff --git a/algo/AlgoApprofondie/cours/modules.txt b/algo/AlgoApprofondie/cours/modules.txt index 5df4b5e..6dd3dad 100644 --- a/algo/AlgoApprofondie/cours/modules.txt +++ b/algo/AlgoApprofondie/cours/modules.txt @@ -7,17 +7,28 @@ définies. Ces modules doivent être aussi indépendants que possible. -module +.. glossary:: - ensemble de ressources liées sémantiquement + module -interface + ensemble de ressources liées sémantiquement - mode d’emploi du module, avec en plus un principe de masquage - des informations (partie publique, partie secrète) + interface + + mode d’emploi 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 l’implantation du type Date.t est **publique**. + +Le Type abstrait de données permet de masquer l’implantation 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 n’ayant pas les mêmes droits sans toucher à + l’implantation. + +.. 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 + +