5. Listes et prédicats fondamentaux
5.1 Éléments, tête et queue
Une liste est une séquence ordonnée, qui peut contenir constantes, variables, termes et autres listes. Les doublons sont possibles. Elle s’écrit entre crochets : [a,b,3,c,pomme,'a b c'], [1,2,3], ou [] pour le vide.
Code (prolog) · sélectionner pour copier
?- [A,B,C] = [30,20,50].
A = 30, B = 20, C = 50.
?- [X|Y] = [30,20,50].
X = 30, Y = [20,50].
?- [a|Y] = [X,b,c].
X = a, Y = [b,c].
[A,B,C] exige exactement trois éléments. Dans [Tete|Queue], la tête est le premier élément et la queue contient tous les autres; pour une liste propre, cette queue est elle-même une liste. Ainsi [a] a pour tête a et pour queue []. La liste vide ne peut pas s’unifier avec une forme exigeant une tête.
Ce découpage permet un parcours sans connaître la longueur à l’avance : examiner la tête, puis appliquer le même prédicat à la queue. Il n’efface pas physiquement un élément de la liste d’entrée; chaque appel considère simplement une sous-structure.
5.2 Appartenance
Contrat : membre(X,L) est vrai si X s’unifie avec un élément de L. Voici les deux clauses du cours, avec _ pour les positions volontairement ignorées :
Code (prolog) · sélectionner pour copier
membre(X,[X|_]).
membre(X,[_|R]) :- membre(X,R).
La première clause reconnaît la tête. La seconde poursuit dans la queue. Aucun cas n’accepte [] : si une liste finie a été parcourue sans correspondance, le résultat est faux, et non une erreur d’exécution. Un avertissement de variable singleton dans la version du support signale une variable présente une seule fois; il n’invalide pas à lui seul la logique. Les _ ci-dessus évitent ces avertissements sans changer les contraintes utiles.
| Requête | Résultat et raison |
|---|---|
membre(a,[a,b,c]) |
vrai : correspondance à la tête |
membre(d,[a,b,c]) |
faux : le parcours atteint le vide |
membre(a,[]) |
faux : aucune clause compatible |
membre(X,[a,b,c]) |
X vaut successivement a, b, c par retour arrière |
membre([a,b],[c,d,[a,b]]) |
vrai : la sous-liste entière est un élément de la liste externe |
L’appartenance ne descend pas automatiquement dans les sous-listes. Des occurrences répétées peuvent aussi fournir plusieurs preuves. Le contrat simple vise les listes finies des exercices.
5.3 Longueur
Code (prolog) · sélectionner pour copier
longueur([],0).
longueur([_|R],N) :- longueur(R,M), N is M+1.
La liste vide a zéro élément. Pour une liste non vide, compter la queue puis ajouter 1. Le contenu de la tête n’intervient pas.
Code (text) · sélectionner pour copier
longueur([a,b,c],N)
→ longueur([b,c],M1)
→ longueur([c],M2)
→ longueur([],0)
← M2 = 0+1 = 1
← M1 = 1+1 = 2
← N = 2+1 = 3
Les appels s’empilent jusqu’au vide; les valeurs nécessaires sont disponibles lors du dépilement. Placer N is M+1 avant le calcul de M risquerait une erreur d’instanciation.
| Requête du cours | Réponse |
|---|---|
longueur([a],N) |
N=1 |
longueur([],X) |
X=0 |
longueur([a,b,c],X) |
X=3 |
longueur(K,0) |
Première réponse : K=[] |
longueur([[a],[b,c]],X) |
X=2 : deux éléments au niveau externe |
longueur([a,Y,c],X) |
X=3, même si Y est libre |
La définition pédagogique utilisant is ne possède pas toutes les possibilités relationnelles du prédicat intégré length/2. Une première réponse inverse correcte, telle K=[], ne garantit pas une énumération inverse terminante.
5.4 Concaténation
Contrat : concat(L1,L2,L3) relie L3 à L1 suivie de L2.
Code (prolog) · sélectionner pour copier
concat([],L2,L2).
concat([X|R1],L2,[X|L3]) :- concat(R1,L2,L3).
Si L1 est vide, le résultat est L2. Sinon, la même tête X apparaît au début de L1 et du résultat; l’appel récursif relie le reste de L1, L2 inchangée et la queue du résultat. Les structures du résultat se construisent par unification avec le patron de la clause.
Pour vérifier concat([a],[b,c],[a,b,c]), la règle impose X=a, R1=[], et la queue de résultat [b,c]. Il reste concat([],[b,c],[b,c]), qui réussit par la base. Le nom local L3 dans la règle représente la queue du résultat de cet appel, et non une variable globale contenant toujours la liste entière.
| Requête | Réponse |
|---|---|
concat([a],[b,c],[a,b,c]) |
vrai |
concat([d],[a,b,c],X) |
X=[d,a,b,c] |
concat([],[a,b,c],L) |
L=[a,b,c] |
concat([a],[],K) |
K=[a] |
concat([d],K,[d,a,b,c]) |
K=[a,b,c] |
concat(K,[a,b,c],[X,a,b,c]) |
K=[X] |
Le même prédicat peut donc vérifier une concaténation, construire un résultat ou retrouver une partie manquante. L’ordre appartient au contrat : inverser simplement L1 et L2 donne généralement une autre liste. Une autre méthode évoquée oralement doit préserver cet ordre pour résoudre le même problème.
5.5 Prédicats prédéfinis et redéfinitions pédagogiques
| Prédicat | Rôle |
|---|---|
member(X,L) |
Appartenance; peut aussi énumérer les éléments |
length(L,N) |
Relation entre liste et nombre d’éléments |
append(L1,L2,L3) |
Concaténation de deux listes dans cet ordre |
reverse(L,R) |
Ordre des éléments inversé |
sort(L,S) |
En SWI-Prolog, tri selon l’ordre standard des termes et suppression des doublons |
Les noms français membre, longueur, concat servent à étudier les mécanismes sans redéfinir les prédicats de bibliothèque. La remarque orale selon laquelle on peut trier dans les deux sens concerne le tri en général : sort/2 n’a pas d’argument de direction. On peut inverser une liste avec reverse/2. Cette précision de bibliothèque est vérifiée dans la documentation primaire SWI-Prolog; le cours ne demande pas de reconstruire ici un algorithme de tri ou d’inversion.
Sur une liste finie, la queue est strictement plus courte. La base lie 0; chaque retour ajoute 1 avec is, après que le résultat récursif est connu.
Source : Ajout pédagogique du portail depuis le maître S07 du cours; aucune source brute diffusée. · 5. Listes