2009-07-08 6 views
4

Ich versuche, ein Prädikat findall in Prolog zu implementieren (ja, ich weiß, dass es eingebaut ist, das ist für eine Aufgabe).PROLOG-Regel gibt nur erste Übereinstimmung zurück

Es wird wie folgt geschrieben:

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(_,_,_, []). 

Aus irgendeinem Grund es gibt mir nur die erste Lösung und hält dort an, als ob der zweite Aufruf von my_findall ausfällt. Wie ich es verstehe, sollte der Backtracking-Mechanismus alle möglichen Optionen umfassen, die alle Optionen für den Aufruf von Pred (N, P) enthalten sollten, obwohl der zweite Aufruf beim ersten Versuch fehlschlagen sollte (die erste Option, die für Pred bereits getestet wurde) wurde behauptet, sollte es alle anderen Optionen zuerst versuchen, bevor Sie aufgeben und gehen zu my_findall ((,), _, []).

Wenn das nicht funktioniert, gibt es eine Möglichkeit, diese Art von Verhalten zu erzwingen, ohne die Lösung komplett neu zu schreiben?

+0

Mit welchem ​​Prolog-Interpreter arbeiten Sie? – liori

+0

Die eingebauten Findalls sind findall/3 und findall/4. Welche versuchen Sie zu implementieren? – Kaarel

Antwort

5

Ihr Pred enthält nicht gebundene Variablen. Wenn Sie in der ersten Iteration Pred aufrufen, sind diese Variablen an erste mögliche Werte gebunden. In Ihrem rekursiven Schritt hat Pred bereits Variablen gebunden, und sie können Werte nicht ändern. Also ... diese Lösung wird nicht funktionieren.

Trace von SWI-Prolog (ich hatte neue/2 Punkt/2 aus irgendwelchen Gründen umbenennen):

Erste Ebene (Aufruf: my_findall (A, B, Element (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 

Wir haben p (A, B) = p (1,2). An diesem Punkt ist A an 1 gebunden, B ist an 2 gebunden.

^ 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, in der Datenbank ist kein Element (1,2) vorhanden.

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

Jetzt ist Element (1,2) wahr. Rekursiven Aufruf:

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

Lassen Sie uns eine andere Lösung erhalten Sie Pred:

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

den unterstrichenen Stück sehen?

Damit diese Technik funktioniert, sollten Sie wahrscheinlich Pred kopieren, indem Sie N und P rekursiv in neue Variablen ändern. Für jede Iteration müssen Sie ein neues Paar von N und P erstellen. Überprüfen Sie copy_term/2 (http://www.swi-prolog.org/pldoc/doc_for?object=copy_term%2f2).