J'ai répondu un peu vite hier, mais plus qu'un type paramétré, ton histoire ressemble à une classe paramétrée par d'autres classes. Dans le jargon des langages ML, on appelle cela des foncteurs : des modules paramétrés par d'autres modules, c'est-à-dire des fonctions des modules dans les modules. Les types paramétriques sont des foncteurs, mais tous les foncteurs de sont pas des types paramétriques (comme les canards sont des animaux, mais les animaux ne sont pas tous des canards).
Pour comprendre un peu ce qu'est un module, prenons cette classe python :
Le problème général du paradigme objet est qu'il confond (de manière totalement ridicule) un concept avec une théorie sur un concept donné. Ici le concept (qui est générique) c'est le type paramétrique A.t et les autres fonctions du modules forment une théorie sur ce concept. Du point du vue du paradigme objet, on se met à dire que c'est la théorie sur A.t, soit le module A, qui définit le concept : c'est inepte. On peut tout à fait étendre la théorie (rajouter des fonctions) sans changer le moins du monde le concept dont elle parle.
Là où cela devient gênant en général, c'est quand on pratique l'héritage. On a coutume de dire, dans le monde de l'orienté objet, que comme un canard est un animal alors la classe canard hérite de la classe animale : c'est faux et absolument faux. La proposition les canards sont des animaux signifie que les canards sont un sous-type (et non une sous-classe) du type animal. Il est rare que des les deux notions de sous-classe et de sous-type se recouvre, en particulier ça ne marche plus dès qu'il y a des opérateurs binaires.
Quittons cette digression sur le monde objet, et revenons à nos modules. Je disais plus haut que les types paramétriques sont des foncteurs, voyons cela avec le type générique des listes.
(* on plonge les types dans le monde des modules *)moduletypeT=sigtypetend(* le type des listes est un foncteur *)moduleListF(A:T)=structtypet=A.tlistend;;moduleListF:functor(A:T)->sigtypet=A.tlistend(* illustration sur les listes d'entiers *)moduleInt_list=ListF(structtypet=intend);;moduleInt_list:sigtypet=intlistend(* pas de problèmes de typage *)([1;2;3]:int_list);;-:int_list=[1;2;3]([1;2;3]:Int_list.t);;-:Int_list.t=[1;2;3]
Maintenant si on veut que notre module paramétré (notre foncteur) n'opère par sur n'importe quel type mais sur des types munis de certaines opérations, on le précise par une contrainte de types sur la signature du paramètres.
(* les contraintes de type sur le paramètre *)moduletypeS=sigtypetvalof_string:string->tvalmeth:t->intend(* notre module paramétré *)moduleA(M:S)=structtypeowner=M.tletf()=M.(meth(of_string"foo"))end
Voilà : A ne connaît absolument rien des modules qui lui seront passés en paramètre si ce n'est qu'ils doivent satisfaire les contraintes de la signature S.
On peut définir ensuite plus loin, dans d'autres entités, des modules à lui passer.
moduleM:S=structtypet=stringletof_stringx=xletmeth=String.lengthendmoduleN:S=structtypet=intletof_strings=tryint_of_stringswith_->0letmethi=iendmoduleB=A(M)moduleC=A(N);;(* note la valeur des types [owner] dans chacune des applications *)moduleB:sigtypeowner=M.tvalf:unit->intendmoduleC:sigtypeowner=N.tvalf:unit->intend(* application de [f] pour les modules résultants *)B.f();;-:int=3C.f();;-:int=0
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Performance
Posté par kantien . En réponse au journal Moi, expert C++, j'abandonne le C++. Évalué à 2.
J'ai répondu un peu vite hier, mais plus qu'un type paramétré, ton histoire ressemble à une classe paramétrée par d'autres classes. Dans le jargon des langages ML, on appelle cela des foncteurs : des modules paramétrés par d'autres modules, c'est-à-dire des fonctions des modules dans les modules. Les types paramétriques sont des foncteurs, mais tous les foncteurs de sont pas des types paramétriques (comme les canards sont des animaux, mais les animaux ne sont pas tous des canards).
Pour comprendre un peu ce qu'est un module, prenons cette classe python :
Dans les langages de la famille ML, on n'utilisera pas de classe pour exprimer cela mais un module :
Le problème général du paradigme objet est qu'il confond (de manière totalement ridicule) un concept avec une théorie sur un concept donné. Ici le concept (qui est générique) c'est le type paramétrique
A.tet les autres fonctions du modules forment une théorie sur ce concept. Du point du vue du paradigme objet, on se met à dire que c'est la théorie surA.t, soit le moduleA, qui définit le concept : c'est inepte. On peut tout à fait étendre la théorie (rajouter des fonctions) sans changer le moins du monde le concept dont elle parle.Là où cela devient gênant en général, c'est quand on pratique l'héritage. On a coutume de dire, dans le monde de l'orienté objet, que comme un canard est un animal alors la classe canard hérite de la classe animale : c'est faux et absolument faux. La proposition les canards sont des animaux signifie que les canards sont un sous-type (et non une sous-classe) du type animal. Il est rare que des les deux notions de sous-classe et de sous-type se recouvre, en particulier ça ne marche plus dès qu'il y a des opérateurs binaires.
Quittons cette digression sur le monde objet, et revenons à nos modules. Je disais plus haut que les types paramétriques sont des foncteurs, voyons cela avec le type générique des listes.
Maintenant si on veut que notre module paramétré (notre foncteur) n'opère par sur n'importe quel type mais sur des types munis de certaines opérations, on le précise par une contrainte de types sur la signature du paramètres.
Voilà :
Ane connaît absolument rien des modules qui lui seront passés en paramètre si ce n'est qu'ils doivent satisfaire les contraintes de la signatureS.On peut définir ensuite plus loin, dans d'autres entités, des modules à lui passer.
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.