Prolog: Vermeiden Sie redundante Auswahlpunkte (Nicht-Determinismus) mit und ohne Schnittoperator

8

Erstens habe ich alle anderen Beiträge zu SO bezüglich der Verwendung von Schnitten in Prolog gelesen und sehe definitiv die Probleme, die mit ihrer Verwendung zusammenhängen. Allerdings gibt es immer noch Unklarheiten für mich und ich möchte das ein für allemal beilegen.

Im folgenden trivialen Beispiel durchlaufen wir rekursiv eine Liste und prüfen, ob jedes zweite Element gleich eins ist. Der rekursive Prozess kann dabei in einem der folgenden Fälle enden: entweder eine leere Liste oder eine Liste mit einem einzelnen Element.

%Vor%

Wenn ausgeführt:

%Vor%

In solchen Situationen habe ich immer einen expliziten Schnittoperator im zweiten Basisfall (d. h. den einen, der ein Element in der Liste darstellt) wie unten verwendet, um den redundanten Auswahlpunkt zu beseitigen.

%Vor%

Jetzt bekommen wir:

%Vor%

Ich verstehe, dass das Verhalten dieses Schnitts für die Position der Regel spezifisch ist und als schlechte Praxis angesehen werden kann.

Weiter könnte man die Fälle jedoch wie folgt neu positionieren:

%Vor%

würde auch den redundanten Auswahlpunkt überflüssig machen, ohne einen Schnitt zu verwenden, aber natürlich würden wir den Auswahlpunkt einfach auf Abfragen mit Listen mit einer geraden Anzahl von Ziffern wie unten verschieben:

%Vor%

Das ist natürlich auch keine Lösung. Wir könnten diese Reihenfolge der Regeln jedoch wie folgt anpassen:

%Vor%

da dies tatsächlich keine Auswahlpunkte übrig lassen würde. Blick auf einige Fragen:

%Vor%

Das Verhalten dieses Schnitts funktioniert jedoch aufgrund der Reihenfolge der Regeln wieder korrekt. Wenn jemand die Basisgehäuse wieder in das ursprüngliche Formular zurücksetzt, wie unten gezeigt:

%Vor%

wir würden immer noch das unerwünschte Verhalten bekommen:

%Vor%

In solchen Szenarien habe ich immer den Single-Cut im zweiten Base-Case verwendet, da ich der einzige bin, der meinen Code durchläuft und ich mich daran gewöhnt habe. Allerdings wurde mir in einer meiner Antworten zu einem anderen SO-Post gesagt, dass dies keine empfohlene Verwendung des Cut-Operators ist und dass ich versuchen sollte, es so weit wie möglich zu vermeiden.

Das bringt mich zu meiner zweiseitigen Frage:

  • Wenn ein Schnitt unabhängig von der Position der Regel, in der er vorhanden ist, das Verhalten ändert, nicht jedoch die Lösung (wie in den Beispielen) oben), gilt es immer noch als schlechte Übung?

  • Wenn ich einen typischen redundanten Auswahlpunkt als den in den obigen Beispielen abschaffen möchte, um ein Prädikat vollständig deterministisch zu machen, gibt es einen anderen, empfohlenen Weg, dies zu erreichen, anstatt Schnitte zu verwenden ?

Vielen Dank im Voraus!

    
SND 12.06.2016, 15:16
quelle

2 Antworten

7

Immer versuchen Sie, !/0 zu vermeiden. Fast immer zerstört !/0 die deklarative Semantik Ihres Programms vollständig.

Alles, was kann ausgedrückt werden durch Mustererkennung sollte durch Mustererkennung ausgedrückt werden. In Ihrem Beispiel:

%Vor%

Wie in Ihrer unreinen Version bleiben für die von Ihnen geposteten Beispiele keinerlei Auswahlpunkte übrig:

%Vor%

Beachten Sie auch, dass in dieser Version alle Prädikate vollständig rein und in allen Richtungen verwendbar sind. Die Beziehung funktioniert auch für die allgemeinste Abfrage und erzeugt Antworten, genau wie wir es von einer logischen Beziehung erwarten:

%Vor%

Keine der von Ihnen geposteten Versionen kann dies aufgrund der unreinen oder nicht deklarativen Prädikate ( !/0 , (=:=)/2 ), die Sie verwenden, verwenden!

Wenn Sie über Listen nachdenken, können Sie fast immer die Mustererkennung verwenden, um die Fälle zu unterscheiden. Wenn das nicht möglich ist, verwenden Sie zum Beispiel if_/3 für die logische Reinheit, während Sie weiterhin eine akzeptable Leistung beibehalten.

    
mat 12.06.2016, 16:24
quelle
2

Der Trick ist das "currying" über die Anzahl der Unbunds in der Regel:

%Vor%

Es ist jedoch eine schlechte Regel zu sagen, dass Schnitte schlecht sind. In der Tat wird mein Favorit sein:

%Vor%

Thing über dieses Beispiel von primes(++) :

%Vor%

vs

%Vor%     
pasaba por aqui 12.06.2016 16:04
quelle