Wir können findall/3
für Listen-Comprehensions verwenden (vgl. die SWI-Prolog-Dokumentation ) ). Z. B.
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:
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)
.
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:
Das integrierte Prädikat bagof/3
behebt dieses Problem. Beachten Sie, dass wir alle lokalen existentiellen Variablen explizit deklarieren müssen:
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.
Derzeit bietet nur B-Prolog eine Form der Listenergänzung:
%Vor%Das zweite Problem wird jedoch nicht behandelt:
%Vor%Tags und Links haskell list-comprehension prolog