5 Stimmen

Einzigartige Ergebnisse aus Prolog

Gibt es einen einfachen Weg, um eine Abfrage in Prolog nur einmal zurückzugeben?

Zum Beispiel versuche ich etwas Ähnliches:

deadly(Xn) :- scary(X), Xn is X - 1, Xp is X + 1, not(safe(Xn)), safe(Xp).
deadly(Xp) :- scary(X), Xn is X - 1, Xp is X + 1, not(safe(Xp)), safe(Xn).

deadly(X).

und bekomme

X = 5

X = 5

X = 5

X = 5

....

Nicht sehr hilfreich für mich.

4voto

Kaarel Punkte 10334

Eine Möglichkeit besteht darin, setof/3 auf das Prädikat anzuwenden, das die Lösungen generiert. Beachten Sie jedoch, dass setof/3 durch Anwendung von sort/2 auf das von bagof/3 gelieferte Ergebnis implementiert ist (zumindest ist dies bei SWI-Prolog der Fall). Wenn Ihr Lösungsgenerator endlos weiterläuft, wird also nie setof/3 angewendet...

Ich würde also sagen, versuchen Sie zu programmieren, sodass Duplikate nicht erzeugt werden, z.B. durch die Verwendung des Cuts (!) an sinnvoller Stelle.

0 Stimmen

Wenn ich mich richtig erinnere, ist `setof` nur nützlich, wenn die Abfrage eine endliche Lösungsgröße hat und weiß, dass sie fertig ist. Andernfalls könnte es einfach weiterhin eine 5 erhalten, sagen "Nein, das habe ich schon bekommen" und erneut suchen und eine ANDERE 5 erhalten... unendliche Schleife.

3voto

starblue Punkte 53167

Wenn ich mich richtig erinnere, gibt es eine Prädikat-Lösung (oder ähnliches, es ist schon lange her, seit ich Prolog programmiert habe), die eindeutige Lösungen in einer Liste sammelt.

Bearbeiten: setof/3 ist das, an das ich gedacht habe. Danke, Kaarel.

3voto

Kaarel Punkte 10334

Ein weiterer Ansatz ist die Memorierung von Lösungen.

:- dynamic seen/1.

% Dies immer aufrufen, bevor deadly_wrapper/1 aufgerufen wird
clear_seen :-
    retractall(seen(_)).

% Dieser Wrapper ruft deadly/1 auf, merkt sich die Lösung mit assert/1 und schlägt fehl,
% wenn die Lösung bereits "gesehen" wurde.
deadly_wrapper(X) :-
    deadly(X),
    (
        seen(X)
    ->  
        fail
    ;
        assert(seen(X))
    ).  

% Dies ist zum Testen.
deadly(1).
deadly(1).
deadly(1).
deadly(5).
deadly(1).
deadly(1).

Falls Ihr Prolog Tabling unterstützt, wird es noch einfacher. Beispiel-Datei:

:- table deadly/1.

deadly(1).
deadly(1).
deadly(5).
deadly(1).
deadly(5).

Beispiel-Ausführung mit XSB:

$ xsb
[xsb_configuration loaded]
[sysinitrc loaded]

XSB Version 3.2 (Kopi Lewak) vom 15. März 2009
[x86_64-unknown-linux-gnu; Modus: optimal; Engine: slg-wam;
 Scheduling: lokal; Wortgröße: 64]

| ?- [deadly_tab].
[Kompilierung von ./deadly_tab]
[deadly_tab kompiliert, CPU-Zeit verwendet: 0,0100 Sekunden]
[deadly_tab geladen]

ja
| ?- deadly(X).

X = 5;

X = 1;

nein
| ?-

0 Stimmen

Ich würde sagen "Memoize", anstelle von "Memorize".

1voto

MarkusQ Punkte 21488

Es ist schwierig zu sagen, ohne mehr von Ihrem Code zu haben, aber Sie suchen wahrscheinlich nach dem cut Operator (!). Wenn Sie die Definition von foo posten möchten, kann ich (oder jemand anderes, der folgt) möglicherweise eine detaillierte/spezifische Antwort geben.

0 Stimmen

Jedes Mal, wenn ich "!" verwendet habe, hat es die Auswertung vollständig gestoppt und ich möchte jeden Wert, den Prolog findet, aber nur einmal pro Wert. (Ich werde versuchen, meinen Fall zu reduzieren)

1 Stimmen

Es geht darum, wann und wo es verwendet wird. Die Aussage "nie wieder hierher kommen" hat eine völlig andere Bedeutung, bevor oder nachdem die Daten zum ersten Mal erfasst wurden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X