2010-11-16 6 views
6

J'apprends le prologue et je suis en train de lire un livre intitulé Programming Prolog for Artificial Intelligence. Comme pratique je veux apprendre comment prolonger un des exemples dans ce livre. Puis-je avoir une aide s'il vous plait?Obtenir la liste des solutions dans Prolog

Supposons que vous avez ces faits:

parent(pam, bob). %pam is a parent of bob 
parent(george, bob). %george is a parent of bob 

Comment pourrais-je écrire un prédicat Prolog qui me donnerait une liste des parents de bobs? Par exemple:

list_parents(bob, L). 

L = [pam, george] ; 
L = [george, pam] ; 
true. 

Répondre

2

Essayez ceci:

parent(pam, bob). %pam is a parent of bob 
parent(george, bob). %george is a parent of bob 
list_parents(A, Es, [X|Xs]) :- parent(X, A), \+ member(X, Es), list_parents(A, [X|Es], Xs). 
list_parents(A, Es, []). 

C'était une méthode inefficace, une meilleure méthode aura besoin d'une « solutions » prédicat d'ordre supérieur.

list_parents (X, Ys): - solutions (parent, [X, W], 1, Ys)

+1

Je posté une question de suivi à votre réponse concernant le prédicat « solutions »: https://stackoverflow.com/questions/47233986/higher-order- solutions-prédicat – mrsteve

12

Un all-solutions prédicat comme findall/3 pourrait faire l'affaire:

list_parents(P, L) :- 
    findall(Parent, parent(Parent, P), L). 

simplement put, findall/3 trouve toutes les liaisons pour Parent dans l'objectif 'backtrack-able' parent(Parent, P), et met toutes les liaisons de Parent dans la liste L. Notez que cela ne supprime pas les doublons, mais vous pouvez faire un sort/2 à L avant de le retourner pour créer un ensemble. L'exécution de cette:

?- list_parents(bob, L). 
L = [pam, george]. 

Si vous n'avez pas findall/3 dans votre implémentation Prolog, on pourrait le faire manuellement comme ceci:

list_parents(P, L) :- 
    list_parents(P, [], L). 

list_parents(P, Acc, L) :- 
    parent(Parent, P), 
    \+ member(Parent, Acc), !, 
    list_parents(P, [Parent|Acc], L). 
list_parents(_, L, L). 

Cette version envoie des appels à list_parents/2 off à une version de l'accumulateur, list_parents/3. Ce dernier essaie également de collecter des liaisons Parent, tant que nous ne les avons pas vues auparavant (d'où le contrôle \+ member), et renvoie la liste dans laquelle aucune nouvelle liaison Parent accumulée dans la liste Acc ne peut être trouvée. L'exécution cela nous donne le même résultat que la première option:

?- list_parents(bob, L). 
L = [pam, george]. 
+1

'findall', c'est ce que j'essayais de Google pour –

+0

sharky, votre implémentation findall ne tient pas compte des éléments répétés. Si vous avez ceci dans la base de données: 'parent (hannah, carl). parent (hannah, carl). parent (bob, carl) .' vos sorties de règles [hannah, bob]. Mais si vous essayez avec findall vous obtenez [hannah, hannah, bob] –