Übersetze Listenverständnis in Prolog

8

Ich habe ein Listenverständnis in Haskell, das ich in Prolog übersetzen möchte.

Der Punkt des Listenverständnisses dreht sich um ein 4 mal 4 Raster:

%Vor%

Jetzt in Prolog habe ich es so übersetzt:

%Vor%

Können wir es besser machen?

    
wvdz 12.04.2014, 19:35
quelle

2 Antworten

8

Wir können findall/3 für Listen-Comprehensions verwenden (vgl. die SWI-Prolog-Dokumentation ) ). Z. B.

%Vor%

Xs ist eine Liste mit allen Werten, die mit X vereinigt werden können, wenn X eine Zahl zwischen 1 und 10 ist. Dies entspricht ungefähr dem Haskell-Ausdruck let Xs = [x | x <- [1..10]] (1). Sie können eine findall/3 -Anweisung so lesen: "Finden Sie alle Werte von [Erstes Argument], so dass [Bedingungen im zweiten Argument] gelten, und schreiben Sie diese Werte in die Liste, [Drittes Argument]".

Ich habe findall/3 verwendet, um ein Prädikat rotate_grid(+Grid, ?RotatedGrid) zu schreiben. Hier ist eine Liste der ungefähren Haskell-Prolog-Äquivalenzen, die ich im Prädikat verwendet habe; Jede Zeile zeigt die Beziehung zwischen dem Wert, mit dem der Haskell-Ausdruck ausgewertet wird, und der Prolog-Variablen mit demselben Wert:

  • a <- [0..3] = A in between(0, 3, A)
  • b <- [0..3] = B in between(0, 3, B)
  • (a + 4 * d) = X in X is A + 4 * D
  • <Grid> !! <Index> = Element in nth0(Index, Grid, Element)

Dann müssen wir einfach alle Werte von Element finden:

%Vor%

Um zu überprüfen, dass dies die richtige Umwandlung ergibt, habe ich den Prolog-Code aus der Frage heruntergeladen und die folgende Abfrage gestellt:

%Vor%

Fußnoten:

(1): between/3 ist nicht das Analogon von [m..n] , da letzterer eine Liste von Werten von m nach n zurückgibt, wo between(M,N,X) X mit jedem Wert zwischen M und N (inklusive) beim Backtracking. Um eine Liste von Zahlen in SWI-Prolog zu erhalten, können wir numlist(M,N,Ns) verwenden. Ein strengeres Analogon für x <- [1.10] wäre also die Konjunktion member(X, Ns), numlist(1, 10, Ns) .

    
Shon Feder 12.04.2014, 20:47
quelle
2

Sie möchten eine Permutation einer Liste. Die Betonelemente werden nicht berücksichtigt. Daher können Sie Ihre Haskell-Signatur zu

verallgemeinern %Vor%

Dies ist bereits ein sehr wertvoller Hinweis für Prolog: Die Elemente der Liste werden nicht berücksichtigt - Elemente werden nicht einmal verglichen. Daher sollte eine Prolog-Lösung in der Lage sein, Variablen direkt zu handhaben, wie zum Beispiel:

%Vor%

Und Ihre ursprüngliche Definition behandelt dies perfekt.

Ihre Version, die List Comprehensions verwendet, schlägt vor, über Backtracking realisiert zu werden, bestimmte Vorkehrungen müssen getroffen werden. Die Verwendung von findall/3 , wie von @aBathologen vorgeschlagen, wird Variablen umbenennen:

%Vor%

Das integrierte Prädikat bagof/3 behebt dieses Problem. Beachten Sie, dass wir alle lokalen existentiellen Variablen explizit deklarieren müssen:

%Vor%

Für Listen, die kürzer als 16 Elemente sind, erzeugt die Haskell-Version einen sauberen Fehler, aber hier erhalten wir ziemlich zufällige Ergebnisse:

%Vor%

Dies liegt an der unklaren Trennung zwischen dem Teil, der ein konkretes Element aufzählt und "erzeugt". Am saubersten ist es, length(Grid, 16) vor dem Ziel bagof/3 hinzuzufügen.

Aufzählung in Prolog

auflisten

Derzeit bietet nur B-Prolog eine Form der Listenergänzung:

%Vor%

Das zweite Problem wird jedoch nicht behandelt:

%Vor%     
false 13.04.2014 10:19
quelle