Inspiré de :
Ce TP a pour objectif :
On définit une liste en mettant des termes entre crochets, et en les séparant par des virgules. En voici des exemples :
Une liste contient des termes : constantes, variables, termes complexes qui peuvent être mélangés. En particulier, une liste peut elle-même contenir d'autres listes
Signalons pour finir que la liste vide (de longueur 0) est représentée par [].
Une liste non vide est divisée en deux parties :
Par exemple,
Le prédicat Prolog "|" (pipe) décompose une liste entre sa tête et sa queue : si on pose la requête
?- [X|Y] = [mia, vincent, jules, yolanda].
Alors :
mia
,
Quelles sont les réponses de Prolog aux requêtes suivantes ?
1. [a,b,c,d] = [a,[b,c,d]]. 2. [a,b,c,d] = [a|[b,c,d]]. 3. [a,b,c,d] = [a,b,[c,d]]. 4. [a,b,c,d] = [a,b|[c,d]]. 5. [a,b,c,d] = [a,b,c,[d]]. 6. [a,b,c,d] = [a,b,c|[d]]. 7. [a,b,c,d] = [a,b,c,d,[]]. 8. [a,b,c,d] = [a,b,c,d|[]]. 9. [] = _. 10. [] = [_]. 11. [] = [_|[]].
Dire lesquelles des listes suivantes sont syntaxiquement correctes. Le cas échéant, donner la taille de la liste.
1. [1|[2,3,4]] 2. [1,2,3|[]] 3. [1|2,3,4] 4. [1|[2|[3|[4]]]] 5. [1,2,3,4|[]] 6. [[]|[]] 7. [[1,2]|4]
Quel résultat donnerait la requête
?- [X|Y] = [].
Et la requête :
?- [X|Y] = [[], dead(zed), [2, [b, chopper]], [], Z].
Même question pour
?- [X,Y | W] = [[], dead(zed), [2, [b, chopper]], [], Z].
Idem avec
?- [_,X,_,Y|_] = [[], dead(zed), [2, [b, chopper]], [], Z].
On montre dans ce qui suit comment vérifier qu'un élément appartient à une liste donné, par récursivité.
On souhaite définir le prédicat element(X,Y), qui sera vrai si l'élément X appartient à la liste Y.
Pour se faire, on constate qu'un élément appartient à une liste :
element(X,[X|T]).
element(X,[H|T]) :- element(X,T).
D'où l'ensemble de clauses définissant le prédicat element(X,Y) :
element(X, [X|T]). element(X, [H|T]) :- element(X,T).
Face à la requête
?- element(yolanda,[yolanda,vincent,jules]).
Prolog va appliquer la première règle pour unifier avec succès
X
à yolanda
,
T
à [trudy,vincent,jules]
.
Par contre, face à la requête
?- element(vincent,[yolanda,vincent,jules]).
Prolog ne peut pas appliquer la première règle : X
ne peut s'unifier simultanément à vincent
et à yolanda
.
Pour exploiter la seconde règle, Prolog unifie :
X
à vincent
,
H
à yoland
,
T
à [vincent,jules]
.
Il doit alors déduire element(vincent,[vincent,jules])
, ce qui s'obtient immédiatement avec la règle 1
Enfin, face à la requête :
?- element(vincent,[yolanda,jules]).
Prolog ne peut pas appliquer la première règle : X
ne peut s'unifier simultanément X
à vincent
et à yolanda
.
Pour exploiter la seconde, il unifie :
X
à vincent
,
H
à yoland
,
T
à [jules]
.
Il doit alors déduire element(vincent,[jules])
X
à vincent
et à jules
).
X
à vincent
,
H
à jules
,
T
à []
.
Il doit alors déduire element(vincent,[])
. Or le prédicat de séparation "|" ne peut pas s'appliquer sur la liste vide.
Bref, Prolog échoue.
On peut faire mieux. Dans la première règle :
element(X,[X|T]).
Nommer la queue par T
est inutile : on ne s'en sert pas dans la partie droite.
Dans ce cas on peut remplacer T
par une variable muette _
, ce qui donne :
element(X,[X|_]).
De même, dans la seconde règle, nommer la tête par H
est inutile :
element(X,[H|T]) :- element(X,T).
On peut là encore remplacer H
par une variable muette _
, ce qui donne :
element(X,[_|T]) :- element(X,T).
Écrire les règles nécessaire à la définition de :
Faire de même avec :
Construire les arbres de décision pour les trois requêtes suivantes :
?- element(a,[c,b,a,y]). ?- element(x,[a,b,c]). ?- element(X,[a,b,c]).
Définir le prédicat a_similaire_b
qui prend deux listes en argument et qui est vrai
Définir le prédicat combine
qui prend trois listes en argument et qui est vrai si la troisième liste est égale à la fusion des deux première en alternant les éléments des deux premières tant qu'il y en a.
On a par exemple les déductions suivantes :
?- combine ([a,b,c],[1,2,3],X). X = [a,1,b,2,c,3]; fail ?- combine ([a,b,c,d],[1,2],X). X = [a,1,b,2,c,d]; fail ?- combine ([a,b],[1,2,3,4],X). X = [a,1,b,2,3,4]; fail