2017-11-03 3 views
0

ich folgende Prolog-Programm haben:Prolog Ergebnis Multiplikation nicht

square([H|T], X) :- 
    squareCompare(T, H, X). 

squareCompare([], X, X * X). 
squareCompare([H|T], V, Result) :- 
    (V * V) < (H * H), 
    squareCompare(T, V, Result); 
    (V * V) > (H * H), 
    squareCompare(T, H, Result). 

Wenn ich ein:

square([7, 5, 2], Result). 

ich Result = 2 * 2, was ich will, ist Result = 4.

Dieses Programm sucht nach dem kleinsten Quadrat des Elements in der Liste.

+4

Dies ist Prolog 101. Sie benötigen 'is/2', um auszuwerten:' X ist 2 * 2'. Bitte, bitte _ bitte_ ein Buch oder eine Dokumentation konsultieren! –

+0

'X * X' ist nicht gleich' X' mal 'X'. Prolog ist in der Tat eine sehr "dünne" Sprache, die ich sagen würde (was meiner Meinung nach eine gute Idee ist). Prolog sieht 'X * X' als' * (X, X) ', also ein Funktor mit zwei Argumenten. –

+0

@ WillemVanOnsem so würde ich SquareCompare ([], X, * (X, X)) tun. Auch ich habe das gesehen http://www.swi-prolog.org/pldoc/man?function=*/2 aber ich brauche ein Beispiel. Können Sie mir ein Beispiel zeigen? – Nameishi

Antwort

3

Neben dem Mangel an Rechen Bewertung (ist/2) wie in den Kommentaren darauf hingewiesen, es gibt auch ein Problem mit </2 mit und >/2: Ihr Prädikat nicht mit aufeinander folgenden Wiederholungen Liste funktioniert, zB:

?- square([7,7],X). 
false. 

wo das erwartete Ergebnis 49. Sie können in Ihrer rekursive Regel von squareCompare/3 </2 von =</2 oder >/2 durch >=/2 durch Ersatz Abhilfe schaffen würde:

squareCompare([], X, Y) :- 
    Y is X*X. 
squareCompare([H|T], V, Result) :- 
    (V * V) < (H * H), 
    squareCompare(T, V, Result); 
    (V * V) >= (H * H), 
    squareCompare(T, H, Result). 

nun das Prädikat das gewünschte Ergebnis liefert:

?- square([7,7],X). 
X = 49. 

Nach einem weiteren Vorschlag in den Kommentaren, können Sie entscheiden, CLP (FD) zu verwenden, das Prädikat Arbeit in beiden Richtungen zu machen. In diesem Fall ähnelt das Prädikat einer wahren Relation, so dass es angebracht wäre, einen aussagekräftigeren Namen zu geben, der diese Tatsache widerspiegelt, etwa list_minsquare/2. Und da Sie sich für das kleinste Quadrat interessieren, warum nicht die Quadrate als Argumente und nicht als Zahlen? Worst Case: Die Wurzel des kleinsten Quadrats ist das letzte Listenelement, dann gibt es keinen Unterschied. Im Idealfall: Die Wurzel des kleinsten Quadrats ist das erste Listenelement, dann berechnen Sie es nur einmal anstelle von Listenlängen. Putting all das zusammen:

:- use_module(library(clpfd)). 

list_minsquare([H|T],X) :- 
    S #= H*H, 
    list_square_minsquare(T,S,X). 

list_square_minsquare([],S,S). 
list_square_minsquare([H|T],S,Result) :- 
    S #< (H*H), 
    list_square_minsquare(T,S,Result). 
list_square_minsquare([H|T],S,Result) :- 
    H2 #= (H*H), 
    S #>= H2, 
    list_square_minsquare(T,H2,Result). 

Jetzt sehen wir uns etwas Aktion. Ihr Beispiel Abfrage liefert das gewünschte Ergebnis:

?- list_minsquare([7,4,2],X). 
X = 4. 

Aufeinanderfolgende Wiederholungen auch Probleme nicht verursachen:

?- list_minsquare([7,7],X). 
X = 49. 

teilweise instanziiert Listen aller möglichen Lösungen führen wird hergestellt:

?- list_minsquare([7,Y,2],X). 
X = 4,      % <- 1st answer: X=4 if 
Y^2#=_G670, 
_G670 in 50..sup ;   % Y^2 is between 50 and sup 
Y in -1..1,     % <- 2nd answer: if Y in -1..1 
Y^2#=X,      % then X=Y^2 
X in 0..1 ; 
X = 4,      % <- 3rd answer: X=4 
Y in -7.. -1\/1..7,   % if Y in -7..-1 or 1..7 
Y^2#=_G1754, 
_G1754 in 4..49.    % and Y^2 in 4..49 

In Im obigen Beispiel gibt es drei Möglichkeiten für Y, von denen keine eine eindeutige Lösung hat, daher erhalten Sie residual Ziele in den Antworten. Wenn Sie konkrete Lösungen bekommen möchten, können Sie den Bereich der Y und fragen Sie nach konkreten Zahlen mit Etikett/1 einschränken:

?- Y in 0..3, list_minsquare([7,Y,2],X), label([Y]). 
Y = X, X = 0 ; 
Y = X, X = 1 ; 
Y = 2, 
X = 4 ; 
Y = 3, 
X = 4. 

Die allgemeinste Abfrage als gut funktioniert. Es ist jedoch die Auflistung der Lösungen in einer unfairen Weise:

?- list_minsquare(L,X). 
L = [_G97],      % <- 1st solution 
_G97^2#=X, 
X in 0..sup ; 
L = [_G266, _G269],    % <- 2nd solution 
_G266^2#=X, 
X in 0..sup, 
X+1#=_G309, 
_G309 in 1..sup, 
_G332#>=_G309, 
_G332 in 1..sup, 
_G269^2#=_G332 ; 
L = [_G494, _G497, _G500],  % <- 3rd solution 
_G494^2#=X, 
X in 0..sup, 
X+1#=_G540, 
X+1#=_G552, 
_G540 in 1..sup, 
_G575#>=_G540, 
_G575 in 1..sup, 
_G500^2#=_G575, 
_G552 in 1..sup, 
_G620#>=_G552, 
_G620 in 1..sup, 
_G497^2#=_G620 ; 
. 
. 
. 

Sie nur eine Lösung für jede Listenlänge, bevor auf die nächste Länge weitergehen. Sie können eine faire Reihenfolge erhalten, indem Sie in der Abfrage eine Ziellänge/2 voranstellen.Dann werden Sie alle Möglichkeiten für jede Liste Länge erhalten, bevor er auf:

?- length(L,_), list_minsquare(L,X). 
L = [_G339],     % <- 1st solution: list with one element 
_G339^2#=X, 
X in 0..sup ; 
L = [_G1036, _G1039],   % <- 2nd solution: list with two elements 
_G1036^2#=X,     % X is square of 1st element 
X in 0..sup, 
X+1#=_G1079, 
_G1079 in 1..sup, 
_G1102#>=_G1079, 
_G1102 in 1..sup, 
_G1039^2#=_G1102 ; 
L = [_G935, _G938],    % <- 3rd solution: list with two elements 
_G935^2#=_G954, 
_G954 in 0..sup, 
_G954#>=X, 
X in 0..sup, 
_G938^2#=X ;     % X is square of 2nd element 
. 
. 
. 

Natürlich können Sie auch einschränken und die Zahlen in der Liste für die obige Abfrage beschriften und Sie werden unendlich in der noch konkrete Zahlen erhalten viele Lösungen (da es unendlich viele Listenlängen gibt).

?- length(L,_), L ins 1..2, list_minsquare(L,X), label(L). 
L = [1], 
X = 1 ; 
L = [2], 
X = 4 ; 
L = [1, 2], 
X = 1 ; 
L = [1, 1], 
X = 1 ; 
L = [2, 1], 
X = 1 ; 
L = [2, 2], 
X = 4 ; 
L = [1, 2, 2], 
X = 1 ; 
L = [1, 2, 1], 
X = 1 ; 
L = [1, 1, 2], 
X = 1 ; 
L = [2, 1, 2], 
X = 1 ; 
. 
. 
. 
Verwandte Themen