Umsetzung der "Letzte" in Prolog
Ich versuche, ein Gefühl für die Prolog-Programmierung durch Ulle Endriss' lecture notes. Wenn meine Lösung zu einer übung verhält sich nicht wie erwartet, ich finde es schwer, eine gute Erklärung. Ich denke, das hat zu tun mit meinem wackeligen verstehen, wie Prolog-Ausdrücke ausgewertet werden.
Übung 2.6 auf Seite 20 Anrufe für eine rekursive Implementierung eines Prädikats last1
verhält sich wie die built-in-Prädikat last
. Mein Versuch lautet wie folgt:
last1([_ | Rest], Last) :- last1(Rest, Last). last1([Last], Last).
Gibt es die richtige Antwort, aber für Listen mit mehr als einem element, die ich habe, um das Semikolon, um die Abfrage zu beenden. Dies macht last1
unterscheidet sich von der integrierten last
.
?- last1([1], Last).
Last = 1.
?- last1([1, 2], Last).
Last = 2 ;
false.
Wenn ich schalten Sie die Reihenfolge, in der ich erklärte, die Regel und die Tatsache, dann Brauch ich den Schlüssel in die Semikolon in beiden Fällen.
Ich glaube, ich weiß, warum Prolog denkt, dass last1
vielleicht noch eine weitere Lösung (also das Semikolon). Ich vorstellen, es folgt die Reihenfolge für die Evaluierung
last1([1, 2], Last).
==> last1([2], Last).
==> last1([], Last). OR Last = 2.
==> false OR Last = 2.
Scheint zu zeigen, dass ich Aussehen sollte für ein Weg, um zu vermeiden matching Rest
mit []
. Egal, ich habe keine Erklärung, warum die Umschaltung der Reihenfolge der Deklaration hätte irgendeinen Effekt.
Frage 1: Was ist die richtige Erklärung für das Verhalten der last1
?
Frage 2: Wie kann ich implementieren Sie ein Prädikat last1
die nicht von der integrierten last
?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Frage 1:
Prolog-Systeme sind nicht immer in der Lage zu entscheiden, ob oder nicht eine Klausel gelten, die vor der Ausführung. Die genauen Umstände sind implementierungsabhängig. Das heißt, Sie kann sich nicht darauf berufen, dass die Entscheidung im Allgemeinen. Systeme verbessern, hier von release zu release. Betrachten als einfachsten Fall:
Sehr clever Prolog erkennen könnte, dass
1 = 2
schlägt immer fehl, und so ganz einfach zu beantwortenX = 1.
statt. Auf der anderen Seite, ist diese "cleverness" ist sehr aufwändig zu implementieren und die Zeit ist besser ausgegeben für die Optimierung der häufigeren Fällen.Also, warum Prologe zeigen dies überhaupt? Der Hauptgrund ist, zu vermeiden, bittet kleinlaut für eine andere Antwort, wenn der Prolog schon weiß, dass es keine weitere Antwort. Also, bevor Sie zu dieser Verbesserung haben, wurden Sie aufgefordert, eine andere Antwort für alle Anfragen mit Variablen und habe die
false
oder "Nein" auf jeder Abfrage genau eine Antwort. Dass dies so umständlich, dass viele Programmierer nie gebeten, für die nächste Antwort, und so wurden nicht gewarnt, um unbeabsichtigte Antworten.Und der sekundäre Grund ist zu halten Sie bewusst die Grenzen der Umsetzung: Wenn der Prolog verlangt nach einer anderen Antwort auf diese Allgemeine Abfrage, dies bedeutet, dass es verwendet immer noch einige Raum, die sich ansammeln könnte, und Essen, bis alle Ihre computing-Ressourcen.
In deinem Beispiel mit
last1/2
Sie Begegnung solchen Fall. Und Sie haben bereits etwas sehr, sehr smart, BTW: Sie versucht, das zu minimieren ist die Abfrage zu sehen, das erste auftreten des unerwarteten Verhalten.In deinem Beispiel-Abfrage
last1([1,2],X)
das Prolog-system nicht Blick auf die gesamte Liste[1,2]
aber sieht nur der AUFTRAGGEBER Funktor. Also für das Prolog-system die Abfrage sieht genauso aus, wielast1([_|_],X)
wenn es entscheidet, welche Klauseln anwenden. Dieses Ziel passt jetzt auf beiden Klauseln, und dies ist der Grund, warum der Prolog erinnert sich an die zweite Klausel als alternative ausprobieren.Aber denken Sie daran: Diese Wahl ist nun möglich, für alle - Elemente, aber das Letzte!!! Das bedeutet, dass Sie zahlen einige Speicher für jedes element! Sie können tatsächlich beobachten, diese durch eine sehr lange Liste. Diese bekomme ich auf meinem kleinen 32-bit-laptop, müssen Sie möglicherweise eine andere null-oder zwei-auf einem größeren system:
Auf der anderen Seite, die vordefinierte
last/2
reibungslos funktioniert:In der Tat, es verwendet Konstante Raum!
Gibt es nun zwei Möglichkeiten, aus dieser:
Versuchen, zu optimieren Ihrer definition. Ja, Sie können dies tun, aber Sie müssen sehr schlau zu sein! Die definition von @back_dragon zum Beispiel ist falsch. Es passiert oft, dass Anfänger versuchen Sie zu optimieren, wenn ein Programm in der Tat sind Sie die Zerstörung Ihrer Semantik.
Fragen Sie sich, ob Sie tatsächlich der Definition das gleiche Prädikat wie
last/2
. In der Tat, sind Sie nicht.Frage 2:
Betrachten:
und
Also Ihre definition unterscheidet sich in diesem Fall mit SWI-definition. Exchange die Reihenfolge der Klauseln ist.
Wieder, dieser
false
! Aber dieses mal, die große Liste funktioniert. Und diese Zeit, die minimal-Abfrage:Ist, und die situation ist ganz ähnlich: auch in Prolog betrachten Sie die Abfrage in der gleichen Weise wie
last2([_|_],E)
und schlussfolgern, dass beide Klauseln gelten. Zumindest haben wir nun Konstanten Aufwand anstelle von linearen Aufwand.Gibt es mehrere Möglichkeiten, um zu überwinden, dass dieser Aufwand in einem sauberen Mode - aber Sie alle hängen stark ab von den Innereien auf eine Umsetzung.
last
ist sicherlich schwieriger, als ich dachte. Ich nahm die Notizen für einen Vortrag vor allem, weil es ist eine kurze Einführung in Prolog, aber jetzt denke ich, dass Die Kunst des Prolog vielleicht die bessere Wahl gewesen. Letztere hat eine bessere Erklärung für das Ausführungsmodell von Prolog.last2/2
schon.SWI-Prolog versucht zu vermeiden, dass weitere Lösungen, wenn es feststellen kann, dass es keine gibt. Ich denke, dass der Dolmetscher untersuchen Sie den Speicher suchen für einige
choice point
Links, und wenn Sie nicht finden können jedem, einfach die Kündigung. Ansonsten wartet Sie, dass sich die Benutzer Wahl zu bewegen.Ich würde versuchen, last1 deterministisch auf diese Weise:
aber ich glaube nicht, dass es
indistinguishable
aus Letzte. Lauern auf den Quellcode der Bibliothek (es ist einfach so?- edit(last).
)können wir schätzen eine gut durchdachte Umsetzung.
last1(Xs,X)
nicht zu einer Antwortedit
. Es wird definitiv in handliches kommen.dieser code funktionieren würde:
es ist, weil prolog-Dinge, es könnte sein, mehr Kombinationen, aber mit diesem symbol: !, prolog gewonnen T go back nach erreichen dieses Punktes
last1(L,N), L = [_,_,_].
erfolgreich sein sollte, aber deine version schlägt.