.
Variante de
Prolog
qui restreint le domaine des termes plus fortement que ne le fait le typage
simple,
et pour laquelle le problème d'unification
est décidable* et unitaire* [Miller 91b],
même quand le
-calcul n'est pas typé
(
unification des termes de
*).
L'idée de
est de substituer à l'axiome de
-équivalence* l'axiome de
-équivalence* qui est moins puissant.
Par définition,
le domaine de est le plus grand sous-ensemble des
-termes
pour lequel la relation de
-équivalence
est égale à la relation de
-équivalence.
Ce domaine peut aussi être caractérisé syntaxiquement
en restreignant la formation des applications :
une variable logique ne peut être appliquée
qu'à des variables essentiellement universelles distinctes et
quantifiées dans la portée de la quantification de la variable logique.
Par exemple,
appartient à
car la variable logique
est appliquée à des
-variables
distinctes.
Au contraire,
,
et
n'appartiennent pas à
car la variable logique
est appliquée soit à une autre variable logique,
ou à deux
-variables identiques,
ou à un terme qui n'est pas essentiellement universel.
Plus subtilement,
appartient à
dans
,
mais pas dans
,
car
n'est pas quantifié
dans la portée de
.
On sait maintenant étendre cette restriction à tous les systèmes
du cube de Barendregt* [Pfenning 91].
L'usage de la
restriction ne s'est pas généralisé,
malgré ses qualités algorithmiques,
car beaucoup de définitions utiles sont exclues de
.
Par exemple,
la définition de sigma* n'est pas
dans
à cause du terme (B _).
Plus généralement,
la programmation à l'ordre supérieur
(où des fonctions sont appliquées à des termes quelconques et pas
seulement à des variables universelles)
est exclue aussi :
voir les prédicats jointure*
et beta_conv*.
En revanche,
la programmation par induction*
sur la structure des termes conduit souvent à des programmes .
De plus,
la restriction
peut être utilisée pendant l'exécution
comme critère heuristique pour
éviter d'utiliser la procédure d'unification générale mais
coûteuse [Brisset et Ridoux 92b, Brisset et Ridoux 92a].
(unification des termes de).
n.f.
(rel.
*)
Problème de vérifier si il existe une substitution
qui peut rendre
égaux modulo la
-équivalence*
deux
-termes* du domaine
,
et de produire une telle substitution quand elle existe (un unificateur).
Le problème est unitaire*
et décidable* [Miller 91b].
Miller propose un algorithme original pour résoudre ce problème,
mais on peut aussi se convaincre qu'il est unitaire est décidable en
examinant le comportement du semi-algorithme de Huet*
lorsqu'il est appliqué à des termes
de ce domaine [Brisset et Ridoux 92b].
Dans le semi-algorithme de Huet,
la simplification* ramène tous les problèmes à des problèmes
flexible-rigide* ou à des problèmes
flexible-flexible*.
Les premiers sont ensuite traités par l´imitation*
et la projection*,
alors que les derniers sont suspendus.
Rappelons aussi que les termes du domaine
ont la propriété
que les seuls termes flexibles ont des arguments qui sont des
variables essentiellement universelles distinctes et
quantifiées dans la portée de la quantification de la variable logique.
En d'autres termes,
ces arguments ne sont pas des constantes.
Deux observations permettent d'adapter le semi-algorithme de Huet
au cas des termes de .
La première est que si l'imitation peut être appliquée
alors la projection ne peut pas l'être,
et vice-versa.
En effet,
de par sa définition,
l'imitation ne peut substituer à l'inconnue de la tête flexible qu'un
terme dont la tête est une constante.
Au contraire,
de par la définition des termes de
,
la projection d'un argument d'un terme de
ne peut que substituer à l'inconnue de la tête flexible un
terme dont la tête n'est pas une constante.
De plus,
comme les arguments d'un termes flexibles de
sont tous distincts,
il y a toujours une seule des projections possibles
qui peut produire une solution.
Donc,
le semi-algorithme de Huet ne calcule pas plus d'un préunificateur par
problème d'unification.
Ce semi-algorithme étant complet pour tout le
-calcul simplement typé*,
il n'y a pas d'autres préunificateurs.
Il faut noter que le choix de la projection ne se fait plus sur un argument
de typage mais sur le nom de l'argument à projeter.
Les types ne sont donc plus nécessaires à l'exécution.
Cependant,
le semi-algorithme de Huet ne calcule que des préunificateurs et laisse
des problèmes flexible-flexible non résolus.
La seconde observation est que un terme flexible de
représente un terme inconnu dans lequel les seules
variables essentiellement universelles qui peuvent avoir une occurrence
sont celles qui sont argument du terme flexible
(
test d´occurrence*).
Le traitement des problèmes flexible-flexible de
devient alors
assez simple.
Il y a deux cas.
Le premier est celui de deux termes flexibles dont les têtes sont différentes.
Il faut substituer aux têtes une nouvelle variable logique dont les arguments
sont tous ceux que les deux termes flexibles ont en commun.
Le second cas est celui de deux termes flexibles dont les têtes sont identiques.
Il faut alors substituer aux têtes
une nouvelle variable logique dont les arguments
sont tous ceux que les deux termes flexibles ont en commun et en même position.
Les deux cas sont exclusifs et chacun deux ne produit qu'une solution.
Ce résultat et celui portant sur les problèmes flexible-rigide montrent que
le problème d'unification
de est unitaire.
On montre que le problème d'unification est décidable en vérifiant que le
semi-algorithme de Huet et le traitement des problèmes flexible-flexible
par la primitive terminent toujours.
Le traitement d'un problème flexible-flexible conduit toujours à son élimination,
n'en produit pas d'autres
et ne produit pas de nouveaux problèmes flexible-rigide.
Seule la terminaison du semi-algorithme de Huet est délicate.
En effet,
trouver une mesure du problème qui décroit strictement par l'application de
l'imitation ou de la projection n'est pas très simple.
Par exemple,
ces opérations peuvent augmenter le nombre d'inconnues du problème ou le nombre
de problèmes flexible-rigide.
Cependant,
certaines inconnues n'en sont pas vraiment.
Par exemple,
celles qui forment la tête flexible d'un problème flexible-rigide
ou flexible-flexible
sont destinées à disparaitre par substitution et ne figurent
dans le problème que parce que l'algorithme n'en traite qu'une à la fois.
Nous les appelons des inconnues fictives.
En particulier,
les introduits par l'imitation ou la projection sont fictives,
car elles vont figurer en tête de problème dès après la simplification
On peut montrer que la mesure constituée d'une paire dont le premier composant est la somme des longueurs des chemins qui mènent à des occurrence d'inconnues fictives et le second composant est la taille des problèmes qui ne contiennent pas d'inconnues fictives décroit pour l'ordre lexicographique à chaque application de l'imitation ou de la projection.
Le semi-algorithme de Huet complété par l'application de la primitive
à tous les problèmes flexible-flexible résiduels constitue donc
un algorithme d'unification pour les termes de
.
La principale différence avec l'algorithme de Miller est que celui-ci
évite de créer les inconnues intermédiaires
au prix d'une exploration
plus détaillée des termes du problème.
.
Notation traditionnelle de la
-abstraction*.
La notation de
Prolog (x
E pour
) permet de
rester dans le cadre de la syntaxe de Prolog.
Libre.
adj.
(ant. lié*)
(
-abstraction*, quantification* et substitution*)
Lié.
adj.
(ant. libre*)
(
-abstraction*, quantification* et substitution*)
Liste homogène.
n.f.
La version typée des listes de Prolog impose généralement
que tous les éléments ont le même type.
On les qualifie d'homogène.
On ne saurait pas utiliser les éléments d'une liste non-homogène
sans l'aide d'une consultation dynamique du type des termes.
Les constructeur du type des listes homogènes sont les suivants :
type nil (list T) .
type '.' T -> (list T) -> (list T) .
Liste en différence.
n.f.
Représentation des listes par la différence entre deux listes.
C'est une représentation très employée en
programmation logique*
car elle conduit à des programmes efficaces en évitant des concaténations
explicites
(
prédicat conc*).
Cependant,
elle recèle quelques difficultés conceptuelles.
En effet,
deux listes
en différence qui dénotent la même liste ne sont pas nécessairement unifiables.
Par exemple,
[1,2]-[2] et [1,3]-[3] dénotent la liste [1],
mais ne sont pas unifiables.
Le programmeur qui utilise les listes en différence devrait donc s'assurer
qu'elles ne rentrent pas dans des problèmes d'unification trop complexes.
C'est en général le cas,
car les listes en différence servent le plus souvent de structure de données
temporaire pour construire des listes standard.
Ce sont ces dernières qui rentrent éventuellement
dans des problèmes d'unification complexes.
Un autre problème est que le test qu'une liste en différence représente une liste
vide nécessite le test d´occurrence* alors que celui-ci
fait défaut dans beaucoup de systèmes Prolog.
Enfin,
la notation M-N n'entraine pas que N est une sous-liste de M.
Ainsi,
l'exemple suivant montre le prédicat de concaténation de trois
listes en différence,
et son utilisation naïve pour spécifier la relation de liste à sous-liste.
type conc3_dl (dlist A) -> (dlist A) -> (dlist A) -> (dlist A) -> o .
conc3_d A-B B-C C-ZC A-ZC .
type sous_liste_dl (dlist A) -> (dlist A) -> o .
sous_liste_dl SousListe Liste :- conc3_dl _ SousListe _ Liste .
Ici, le prédicat conc3_dl est essentiellement utilisé en mode* (conc3_dl ? ? ? +) alors qu'il ne peut fonctionner qu'en mode (conc3_dl + + + ?).
Liste fonctionnelle.
n.f.
Représentation des listes par des fonctions.
La représentation fonctionnelle FL d'une liste L
est une fonction qui quand on l'applique à la représentation
classique d'une liste M
produit la représentation
classique de la liste L
M.
La liste nil est représentée par
,
tandis que le constructeur de concaténation est représenté
par
.
En d'autres termes,
la liste vide est représentée par la fonction identité,
tandis que la concaténation est la composition de fonctions.
La correspondance entre la représentation traditionnelle et la
représentation fonctionnelle est décrite par le prédicat
liste_fliste*,
et la représentation de la liste vide et de la concaténation sont
des solutions de la spécification d'un monoïde donnée
par le prédicat monoïde*.
La représentation fonctionnelle a les avantages notationnels des listes en différence*, sans en avoir les inconvénients [Brisset et Ridoux 91]. Par exemple, le prédicat suivant représente la relation entre une sous-liste et une liste, alors que cela n'est pas possible avec les listes en différence.
type sous_liste ((list A)->(list A)) -> ((list A)->(list A)) -> o .
sous_liste SousListe z(_ (SousListe (_ z))) .
La mise en uvre de la représentation fonctionnelle
est cependant plus coûteuse.
Cela vient de ce que la concaténation des listes en différence réalise une
-réduction* au moindre coût
en prenant le risque d'être incorrecte.
Avec la représentation fonctionnelle,
la
-réduction est toujours correctement implémentée,
mais en faisant des opérations qui ne sont pas toujours nécessaires.
Littéral.
n.m.
Formule atomique* éventuellement niée. Les formules
et
sont des littéraux,
mais
n'en est pas un.
Logique combinatoire.
n.f.
Théorie des combinateurs* et de leur
propriétés [Curry et al. 68, Hindley et Seldin 86].
Cette théorie a été introduite par Shönfinkel,
puis développée par Curry*.
Par exemple,
est un théorème de la logique combinatoire :
pour tout
,
égale
qui égale
.
.
Première implémentation de
Prolog.
Elle n'est ni complète ni efficace.
Elle a été écrite entre 1986 et 1988 par Dale Miller et Gopalan Nadathur à
l'université de Pennsylvanie (UPenn).
Il s'agit d'un interpréteur écrit en Prolog.
l_terme.
ex.progr.
(rel.
-terme*)
Constructeurs de
-termes purs de niveau objet.
kind l_terme type .
type app l_terme -> l_terme -> l_terme .
type abs (l_terme->l_terme) -> l_terme .
Le -terme
sera représenté par
(abs x
(app x x)).
Noter que les métatermes de type l_terme représentent des
-termes purs,
y compris des termes qui ne sont pas simplement typables.
Il n'y a pas besoin d'un constructeur pour les occurrences de variables. En effet, le constructeur abs signale une abstraction. On peut alors appliquer son argument à n'importe quel terme qu'on saura reconnaître. Une variable universelle joue très bien ce rôle. Les occurrences de la variable liée coïncideront avec les occurrences du terme «reconnaissable».
Les différents rédex* de niveau objet peuvent être identifiés de la manière suivante :
type (beta_redex, beta_eta_redex, eta_redex) l_terme -> o .
beta_redex (app (abs E) F) .
eta_redex (abs (app E)) .
beta_eta_redex (app (abs (app E)) F) .
l_terme_st.
ex.progr.
(rel.
-terme simplement typé*)
Constructeurs de
-termes simplement typés de niveau objet.
Les types du niveau objet sont représentés directement par les types du
métalangage,
Prolog.
Si un métaterme est bien typé,
alors le terme objet qu'il représente l'est aussi.
Il n'y a donc pas besoin d'un prédicat explicite de vérification de type.
kind l_terme_st type -> type .
type app_st (l_terme_st A->B) -> (l_terme_st A) -> (l_terme_st B) .
type abs_st ( (l_terme_st A)->(l_terme_st B) ) -> (l_terme_st A->B) .