2009-07-08 6 views
4

J'essaie d'implémenter un prédicat findall dans Prolog (oui, je sais qu'il est intégré, c'est pour une affectation).La règle PROLOG renvoie uniquement le premier résultat

Il est écrit comme suit:

my_findall(N,P,Pred,L) :- Pred, not(new(N,P)), !, assert(new(N,P)), my_findall(N1,P1,Pred,L1), L=[N,P,L1], retract(new(N,P)). 
my_findall(_,_,_, []). 

Pour une raison quelconque, il ne me donne que la première solution et arrête là, comme si le second appel à my_findall échoue. Si je comprends bien, le mécanisme de backtracking devrait passer en revue toutes les options possibles, qui devraient inclure toutes les options pour appeler Pred (N, P), même si le second appel échoue au premier essai (la première option essayée pour Pred a déjà été affirmé), il devrait essayer toutes les autres options avant d'abandonner et aller à my_findall ((,), _, []).

Si ce n'est pas comme cela que cela fonctionne, existe-t-il un moyen de forcer ce type de comportement sans réécrire complètement la solution?

+0

Avec quel interpréteur prologue travaillez-vous? – liori

+0

Les findalls intégrés sont findall/3 et findall/4. Lequel essayez-vous de mettre en œuvre? – Kaarel

Répondre

5

Votre Pred contient des variables non liées. Quand dans la première itération vous appelez Pred, ces variables sont liées aux premières valeurs possibles. Dans votre étape récursive, Pred a déjà des variables liées et ne peut pas changer de valeur. Donc ... cette solution ne marchera pas.

Trace de SWI-Prolog (je devais renommer nouveau/2 au point/2 pour certaines raisons):

premier niveau (appel: my_findall (A, B, membre (p (A, B), [p (1,2), p (3,4)]), L).

Call: (7) my_findall(_G819, _G820, member(p(_G819, _G820), [p(1, 2), p(3, 4)]), _G840) ? creep 
    Call: (8) lists:member(p(_G819, _G820), [p(1, 2), p(3, 4)]) ? creep 
    Exit: (8) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep 

Nous avons obtenu p (A, B) = p (1,2). A ce point A est lié à 1, B est lié à 2.

^ Call: (8) not(item(1, 2)) ? creep 
    Call: (9) item(1, 2) ? creep 
    Fail: (9) item(1, 2) ? creep 
^ Exit: (8) not(item(1, 2)) ? creep 

Ok, il n'y a pas d'objet (1,2) dans la base de données.

^ Call: (8) assert(item(1, 2)) ? creep 
^ Exit: (8) assert(item(1, 2)) ? creep 

Maintenant l'élément (1,2) est vrai. appel récursif:

Call: (8) my_findall(_L215, _L216, member(p(1, 2), [p(1, 2), p(3, 4)]), _L199) ? creep 

Obtenons une autre solution ne Pred:

Call: (9) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep 
          ^^^^^^^ 

Voir la pièce soulignée?

Pour que cette technique fonctionne, vous devez probablement copier Pred, en changeant récursivement N et P dans de nouvelles variables. Pour chaque itération, vous devez "créer" une nouvelle paire de N et P. Vérifiez copy_term/2 (http://www.swi-prolog.org/pldoc/doc_for?object=copy_term%2f2).

Questions connexes