Interroger : une question, tous les sens
Une fois le programme chargé et saturé, tu poses une question — ?- But. — et Fix te donne toutes les réponses. Pas un « appel » de fonction : une relation qu'on interroge, dans le sens qu'on veut.
Prenons un petit programme :
parent(tom, bob).
parent(bob, ann).
parent(bob, liz).
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
Toutes les réponses, pas la première
?- grandparent(tom, X).
X = ann
X = liz
La requête énumère toutes les solutions, pas seulement une. Il n'y a pas de « retour » unique : il y a l'ensemble des X qui rendent le but vrai.
La même relation, dans l'autre sens
La question n'a pas de sens privilégié. La variable peut être à gauche :
?- grandparent(X, ann).
X = tom
Même relation, même règle — on demande cette fois « de qui ann est-elle petite-fille ? ». Rien à recoder : une relation répond dans tous les sens où on l'interroge. C'est ce qu'on appelle les modes — et Fix n'en impose aucun.
Une question fermée : vrai ou faux
Sans variable, la requête devient une vérification :
?- grandparent(tom, ann).
true.
?- grandparent(ann, tom).
false.
true si le fait est dérivable, false sinon. Pas d'exception, pas de « null » : une réponse nette.
Sur l'état saturé
Tu interroges toujours le point fixe déjà calculé : toutes les conséquences du programme sont là avant même la question. La requête ne « lance » pas un calcul récursif à la demande — elle lit ce qui est vrai. Et comme Fix termine toujours, l'énumération des solutions est finie.
Les bords honnêtes
- Une requête lit l'état saturé ; elle ne modifie rien (pour ajouter/retirer, c'est
:assert/:retract). - L'ordre des solutions suit l'ordre de dérivation, pas un tri — ne compte pas dessus.
À côté
- L'unification — le mécanisme qui lie les variables sous la question.
:help query— la fiche, dans le REPL.- Référence : fiches — commandes, builtins, concepts.