• Aucun résultat trouvé

Historiquement, le syst`eme de Mycroft et O’Keefe [Mycroft et O’Keefe 84] impl´e- mente la premi`ere discipline de type prescriptif pour Prolog. C’est une transposition de la discipline deML[Milner 78] `a Prolog. Leur proposition a soulev´e quelques interrogations

[Hanus 89a, Hanus 89b, Hanus 91] et a abouti `a la d´efinition d’un Prolog typ´e, Typed Pro-

log [Lakshman et Reddy 91]. Le syst`eme G¨odel [Hill et Topor 92, Hill et Lloyd 94] met

aussi en œuvre cette discipline. `A notre connaissance, Typed Prolog n’a pas ´et´e impl´ement´e ni diffus´e. G¨odel,



Prolog et, depuis peu, Mercury [Somogyi et al. 96] sont probablement les seuls langages de programmation logique typ´es prescriptivement `a avoir ´et´e impl´emen- t´es en vraie grandeur et avoir ´et´e utilis´es relativement largement. On peut donc d´ej`a tirer quelques enseignements de ces exp´eriences. Le syst`eme de type de Mycroft et O’Keefe a ´et´e aussi impl´ement´e sous la forme d’un outil de v´erification de programmes. Cependant, l’usage de cet outil reste optionnel. Cela ne confronte pas le programmeur `a l’obligation de ne produire que des programmes bien typ´es.

Le point positif, pr´evisible, est que beaucoup d’erreurs sont d´ecouvertes d`es la compila- tion. Elles vont de l’oubli ou la permutation de param`etres `a la faute de frappe. De plus, en cas de type non d´eclar´e, le syst`eme Prolog/MALIpropose un type dans le message d’erreur. Cela signifie que mˆeme si nous avons souhait´e ne pas fonder la notion de programme bien typ´e sur l’inf´erence de type, le syst`eme Prolog/MALIl’utilise op´erationnellement comme un m´ecanisme d’assistance au programmeur.

Le point n´egatif vient de ce que la discipline de type mise en œuvre est parfois trop rigide et interdit certaines pratiques bien ´etablies en programmation logique. Nous pensons que certaines de ces pratiques sont nuisibles, et que le typage ne fait que le r´ev´eler. Par exemple, le typage de Prolog/MALIinterdit d’utiliser un symbole avec desarit´es(68)diff´e-

rentes. Nous pensons que c’est une bonne chose car permettre cet usage empˆeche de d´etec- ter les omissions de param`etre. La confusion entre le contenant et le contenu (par exemple, liste et ´el´ement) est aussi fr´equente et reconnue nuisible [O’Keefe 90]. Par exemple, consi- d´erons le pr´edicat qui relie un arbre binaire et la liste de ses feuilles. C’est un classique o`u les deux premi`eres clauses ont pour premier argument une liste d’´el´ements, alors que la troisi`eme a pour premier argument un ´el´ement.

aplatir [] []:– ! .

aplatir [L1

|

L2] F3:– ! , aplatir L1 F1 , aplatir L2 F2 , conc F1 F2 F3 .

aplatir E [E] .

La version bien typ´ee de ce pr´edicat est la suivante :

kind arbre2 type –

>

type .

type feuille F –

>

(arbre2 F) .

type nœud (arbre2 F) –

>

(arbre2 F) –

>

(arbre2 F) .

type aplatir (arbre2 F) –

>

(list F) –

>

o . aplatir (feuille F) [F] .

aplatir (nœud G D) Fs:– aplatir G FG , aplatir D FD , conc FG FD Fs .

Il faut noter que mˆeme reconnu nuisible par certains, ce genre de pratique abonde dans la litt´erature, et la position qui consiste `a d´efendre une discipline de typage (donc de pro- grammation) contre la pratique courante n’est pas confortable.

Il subsiste d’authentiques points n´egatifs dont certains ont trait `a la

m´etaprogrammation(104). Ici, la difficult´e est que mˆeme si les formules et les termes

de



Prolog sont bien adapt´es `a la m´etaprogrammation, les types de



Prolog ne le sont pas compl`etement. Un des enjeux de la m´etaprogrammation est de sous-traiter `a la machine du m´etalangage des op´erations du niveau objet quand langage objet et m´etalangage sont proches. Par exemple, si on a des langages de programmation logique

aux deux niveaux, il est int´eressant de sous-traiter l’unification des termes objet `a la proc´edure du m´etalangage, et c’est quelque chose qui se fait tr`es bien (voir le vanilla interpreter(140)[Sterling et Shapiro 90]). De fa¸con similaire, on voudrait que le typage des

termes objet soit sous-trait´e au m´eta-langage (seulement s’il est compatible, ´evidemment). Il se trouve que la discipline de type de



Prolog est trop faible pour pouvoir faire cela avec les types polymorphes. On voudrait appliquer au typage des termes objet la discipline du m´etalangage (ici,



Prolog), de telle sorte qu’un terme objet est bien typ´e si et seulement si le m´etaterme qui le repr´esente l’est aussi. Cela marche assez bien, sauf pour le polymor- phisme. Par exemple, essayons d’appliquer aux deux membres d’une paire polymorphe une fonction polymorphe inconnue mais qui sera le r´esultat d’un calcul (c’est-`a-dire une fonction objet).

kind paire type –

>

type –

>

type . type p A –

>

B –

>

(paire A B) .

type appliquer `a paire (U –

>

U) –

>

(paire V W) –

>

(paire V W) –

>

o .

appliquer `a paire F (p G D) (p (F G) (F D)) .

Ce programme ne r´epond pas `a notre besoin car le typage g´en´erique force les trois types inconnus, U, V et W, `a ˆetre ´egaux. Pour cette application, le type inconnu U ne devrait pas ˆetre trait´e comme le sont V et W. On voudrait pouvoir prendre une instance nouvelle de son type pour chaque application de la fonction F. Ce n’est pas possible lorsque le poly- morphisme est repr´esent´e par des formules uniquementpr´enexes(109): durant l’ex´ecution,

le type d’un terme ne peut donc ˆetre qu’une instance monomorphe d’un type polymorphe, mais jamais un type polymorphe.

Le probl`eme pos´e peut sembler tr`es sp´ecifique et ne m´eriter qu’une r´eponse locale. En fait, il est assez g´en´eral et le programmeur



Prolog fait souvent de la m´etaprogrammation sans le savoir. Il faut se rappeler aussi le sens assez large que nous avons donn´e `a m´etapro- grammation. On peut se demander alors pourquoi ce probl`eme n’est pas aussi apparu dans un autre langage polymorphe g´en´erique commeML. En fait, il est apparu [Dubois et al. 95] mais peut ˆetre pas avec la mˆeme acuit´e pour une raison qui semble en partie culturelle. Il n’y a pas enMLd’op´erations g´en´eriques que l’on voudrait r´eutiliser au niveau objet, alors que la programmation logique utilise depuis ses d´ebuts des op´erations g´en´eriques comme l’unification, la comparaison de termes, la d´ecomposition de terme (pr´edicat =.., alias univ), etc.

Une autre difficult´e est le statut de la condition de tˆete(79). Celle-ci pr´ecise que non

seulement chacune des clauses doit ob´eir `a la discipline de typage g´en´erique, toutes les occurrences d’une mˆeme variable ont le mˆeme type et toutes les occurrences d’une mˆeme constante ont des types qui sont des instances ind´e- pendantes d’un mˆeme type polymorphe,

mais aussi que les clauses d’un mˆeme pr´edicat doivent((s’accorder)),

les constantes pr´edicatives en tˆete des clauses d’un mˆeme pr´edicat doivent avoir les mˆemes types.

Par exemple, la condition de tˆete fait que le pr´edicat suivant est mal typ´e.

pred ad hoc 1 . % Type de pred ad hoc : int –

>

o. pred ad hoc ”1” . % Type de pred ad hoc : string –

>

o.

Cette condition a ´et´e exhib´ee pour r´epondre `a des questions de correction s´emantique du typage et d’inf´erence de type. Un programme bien typ´e qui satisfait la condition est s´e- mantiquement correct, c’est-`a-dire qu’il ne causera pas d’erreur de type durant l’ex´ecution. En revanche, l’inf´erence de type polymorphe est ind´ecidable en pr´esence de cette condi- tion. Il faut le savoir, mais ce n’est pas une limitation tr`es grave car on peut sp´ecialiser un peu le probl`eme pour le rendre d´ecidable [Lakshman et Reddy 91]. Ce qui est plus grave est que la condition de tˆete interdit quasiment le polymorphisme ad hoc. On ne peut re- trouver le polymorphisme ad hoc qu’au prix de tol´erer des constructeurs qui ne sont pas

transparents(80): des constructeurs dont le type contient des variables qui n’apparaissent pas

dans le type du r´esultat. Par exemple cons :

A

!(

list A

)!(

list A

)est transparent, mais

f :(

list A

)!

int

ne l’est pas. On remarque qu’aucun constructeur de pr´edicat polymorphe

n’est transparent. Ils ont tous un type de la forme

:::A:::

!

o

.

Ce faisceau de circonstances un peu contradictoires fait qu’il n’y a pas de consensus sur l’adoption de la condition de tˆete. Nous l’avons adopt´ee dans Prolog/MALIparce qu’elle permet la compilation et la v´erification de type s´epar´ees, tout en sachant qu’elle contribue `a aggraver la rigidit´e du typage, contrairement aux autres impl´ementations de



Prolog qui ne l’adoptent pas [Nadathur et Pfenning 92]. Il faut noter que, dans leurs premiers articles sur



Prolog, Miller et Nadathur ne se prononcent pas sur cette condition [Nadathur 87].

Lacorrection s´emantique(83)est la propri´et´e d’un syst`eme de v´erification de type qui

est tel qu’aucun programme bien typ´e selon ce syst`eme ne peut causer d’erreur de type `a l’ex´ecution (en anglais,((Well-typed programs cannot go wrong))[Milner 78]).

L’int´erˆet de la correction s´emantique et qu’elle permet de ne plus repr´esenter de types durant l’ex´ecution car leur correction peut ˆetre ´etablie d`es la compilation. Cependant, on peut avoir d’autres raisons de repr´esenter les types que pour les v´erifier. En



Prolog, l’op´eration de projection(111) les utilise pour s´electionner les arguments `a projeter. Cela

signifie que mˆeme quand la correction s´emantique est ´etablie, il faut repr´esenter suffi- samment de type pour contrˆoler la projection. Notre impl´ementation repr´esente donc des types durant l’ex´ecution, mais pas tous loin s’en faut [Brisset 92, Brisset et Ridoux 92b, Brisset et Ridoux 94]. Le polymorphisme g´en´erique n’´eclaire pas tellement le statut de ces types repr´esent´es durant l’ex´ecution. Ils apparaissent comme param`etres cach´es des termes et des pr´edicats, ils subissent l’unification comme les termes, mais contrˆolent aussi l’uni- fication des termes. Ils peuvent en particulier se propager par substitution et empˆecher l’unification de deux termes sans que la syntaxe ne le laisse pr´evoir.

Un dernier point est que le polymorphisme g´en´erique fait perdre la propri´et´e de trans- parence d´efinitionnelle. Dans le contexte de la programmation logique, ˆetre transparent d´efinitionnellement signifie que l’on peut toujours remplacer un terme par une variable en ajoutant la contrainte que cette variable est ´egale `a ce terme. C’est la base d’une forme normale des programmes utilis´ee pour les compiler, les analyser, ou calculer la compl´etion de Clark [Clark 78] des programmes avec n´egation.

Par exemple, une clause

. . . :– . . . , (p . . . t . . . ) , . . . , (q . . . t . . . ) , . . . .

peut ˆetre transform´ee en

Les types des deux occurrences de t peuvent ˆetre diff´erents, alors que les types des deux occurrences d’utilisation de X ne peuvent qu’ˆetre ´egaux. Le polymorphisme g´en´erique in- troduit des variables cach´ees (les variables de type) qui empˆechent d’appliquer les trans- formations habituelles.

La discipline de typage polymorphe g´en´erique inspir´ee deMLne nous semble donc pas compl`etement adapt´ee `a Prolog et



Prolog.