Verwenden Sie Schnitt in Prolog, um eine Funktion once_member / 2 zu definieren

8

Disclaimer: Dies ist eine informelle und nicht bewertete Kursarbeit in meiner eigenen Zeit. Ich habe es selbst versucht, bin gescheitert und suche jetzt nach einer Anleitung.

Ich versuche eine Version der Funktion member / 2 zu implementieren, die nur einmal Mitglieder für eine Liste zurückgibt.

Zum Beispiel:

%Vor%

Ich möchte nur jede Nummer maximal einmal ausdrucken.

%Vor%

Uns wurde gesagt, dass wir das mit dem Schnitt machen sollen! Betreiber aber ich habe mir die Notizen zu meinem Kurs für Schnitt und mehr online angeschaut und trotzdem kann es mir nicht in den Kopf klicken!

Bisher habe ich es geschafft:

%Vor%

Was 1 und dann nichts anderes zurückgibt, habe ich das Gefühl, dass mein Schnitt an der falschen Stelle ist und einen Backtrack für jedes mögliche Match verhindert, aber ich bin mir wirklich nicht sicher, wohin ich als nächstes gehen soll.

Ich habe in meinen Kursunterlagen nachgeschaut und auch: Ссылка und Programmierung in Prolog (Google Bücher)

Eine Anleitung, wie man den Cut logisch anwendet, wäre am nützlichsten, aber die Antwort könnte mir helfen, das herauszufinden.

Es wurde uns auch gesagt, dass wir eine andere Methode anwenden sollen, die '\ +' Negation durch Fehler verwendet, aber hoffentlich ist das einfacher, wenn der Schnitt für mich erst einmal funktioniert hat?

    
Peter Hamilton 26.11.2011, 23:36
quelle

4 Antworten

-1

Hier ist ein Ansatz, der einen Schnitt in der Definition von once_member / 2 zusammen mit dem klassischen member / 2 Prädikat verwendet:

%Vor%

Angewandt auf das obige Beispiel:

%Vor%

Hinweis: once_member / 2 ist trotz der seltsam erscheinenden Definition mit drei Klauseln die letzte / tail-rekursive Optimierung, die aufgrund der Platzierung des vorherigen Schnitts in Frage kommt seine erste Selbstinvokation.

    
hardmath 27.11.2011, 14:51
quelle
2

Entfernen Sie überflüssige Antworten und bleiben Sie rein!

Wir definieren memberd/2 basierend auf if_/3 und (=)/3 :

%Vor%

Insbesondere bei Meta-Prädikaten kann eine andere Argument-Reihenfolge manchmal nützlich sein:

%Vor%

Beispielabfrage:

%Vor%     
repeat 03.04.2015 13:27
quelle
1

Die Lösung mit Schnitt ... zunächst klingt es ziemlich mühsam.

Unter der Annahme, dass das erste Argument instanziiert wird, ist eine Lösung trivial:

%Vor%

aber dies wird nicht das gewünschte Verhalten haben, wenn das erste Argument nicht instanziiert wird.
Wenn wir die Domäne der Listenelemente kennen (zum Beispiel Zahlen zwischen 1 und 42), könnten wir das erste Argument instanziieren:

%Vor%

aber das ist sehr ineffizient

An diesem Punkt begann ich zu glauben, dass es nicht möglich ist, mit nur einem Schnitt zu tun (vorausgesetzt, dass wir nicht + oder list_to_set / 2
verwenden Oh, Moment mal! & lt; Fügen Sie Idee Emoticon hier & gt;

Wenn wir ein Prädikat (wie list_to_set / 2 von swi-prolog) implementieren könnten ) das würde eine Liste nehmen und eine Liste erzeugen, in der alle doppelten Elemente entfernt werden, wir könnten einfach das normale Mitglied / 2 verwenden und keine doppelten Ergebnisse erhalten. Probieren Sie es aus, ich denke, dass Sie es selbst schreiben können.

-------- Spoiler ------------

%Vor%

Wie Sie sehen, müssen wir einen Ausschnitt in remove_all / 3 verwenden, weil sonst die dritte Klausel mit remove_all(X,[X|_],_) übereinstimmen kann, da wir nicht angeben, dass sich H von X unterscheidet. Ich glaube, dass die Lösung mit not einfach ist.

Btw, die Lösung mit nicht konnte als deklarativer als die Lösung mit Schnitt gekennzeichnet werden; Der Schnitt, den wir verwendet haben, wird normalerweise als roter Schnitt bezeichnet, da er das Verhalten des Programms verändert. Und es gibt andere Probleme; Beachten Sie, dass remove_all(1,[1,2],[1,2]) selbst mit dem Schnitt erfolgreich sein würde.

Andererseits ist es nicht effizient, zweimal nach einem Zustand zu suchen. Daher wäre es optimal, die if-then-else-Struktur zu verwenden (aber ich nehme an, dass Sie sie auch nicht verwenden dürfen; ihre Implementierung kann mit einem Schnitt erfolgen).

Auf der anderen Seite gibt es eine andere, einfachere Implementierung mit nicht: Sie sollten nicht nur überprüfen, ob X ein Mitglied der Liste ist, sondern auch, wenn Sie es schon einmal gesehen haben; Du brauchst also einen Akku:

------------- Spoiler --------------------

%Vor%     
Thanos Tintinidis 27.11.2011 00:35
quelle
1
%Vor%

Wie fast alle anderen veröffentlichten Lösungen, hat dies einige Anomalien.

%Vor%     
false 28.11.2011 08:34
quelle

Tags und Links