2016-05-10 6 views
1

Ich habe versucht, eine Liste der Struktur zu sortieren.Prolog Sortierung einer Liste der Struktur, arithmetischer Fehler

Die Struktur ist wie dies

% person(Name, Weight). 
person(tom, 65). 
person(dan, 70). 
person(mike, 80). 

Und die Liste wie dies

List = [person(tom, 65), person(dan, 70), person(mike, 80)]. 

Ich mag die Liste sortieren von größtem Gewicht zu dest wäre. Wie folgt aus:

SortList = [person(mike, 80), person(dan, 70), person(tom, 65)]. 

Bisher habe ich dies:

sortListPerson([], []). 
sortListPerson([person(NameP, WP)|Rest], Result):- 
    sortListPerson(Rest, List), 
    insertPerson(person(NameP, WP), List, Result). 

insertPerson(person(NameP, WP), [], [person(NameP, WP)]). 
insertPerson(person(NameP1, WP1), [person(NameP2, WP2)|Rest], [person(NameP1, WP1)|List]):- 
    integer(WP1), 
    integer(WP2), 
    WP1 @>= WP2, 
    insertPerson(person(NameP2, WP2), Rest, List). 
insertPerson(person(NameP1, WP1), [person(NameP2, WP2)|Rest], [person(NameP2, WP2)|List]):- 
    integer(WP1), 
    integer(WP2), 
    WP1 @< WP2, 
    insertInPlace(person(NameP1, WP1), Rest, List). 

ich mit einer Liste von zwei Personen versucht haben und es funktioniert:

?- sortListPerson([person(a, 10), person(b, 30)], SortList). 

SortList = [person(b,30),person(a,10)] ? ; 

Aber wenn ich versuche, mit einem Liste von 3 oder mehr Personen erscheint ein Fehler:

?- sortListPerson([person(a, 10), person(b, 30), person(c, 40)], SortList). 
{ERROR: arithmetic:>=/2 - expected an arithmetically evaluable expression, found person(a,10)} 

no 
?- 

Kann jemand helfen?

+1

Sie eigentlich nicht haben 'Person (Name (Weight). 'Geschrieben als eine Tatsache, oder? – lurker

+2

Ich sehe nicht, dass '> =/2 'irgendwo in dem Code verwendet wird, den Sie anzeigen, aber der Fehler bezieht sich eindeutig auf diesen Operator. Vielleicht gibt es ein Problem in Ihrem 'insertInPlace/3' Prädikat, das nicht gezeigt wird. – lurker

+1

@Danick: Gibt es einen Grund, warum Sie das Tag [tag: clpfd] bearbeitet haben? Es scheint für Ihre Frage relevant zu sein; http://stackoverflow.com/tags/clpfd/info. – Matt

Antwort

5

So wie ich es sehe Ihre einschub Art in Ordnung ist, mit Ausnahme der zweiten Klausel insertPerson/3:

 
:- use_module(library(clpfd)). 

insertPerson(person(N,W), [], [person(N,W)]). 
insertPerson(person(N1,W1), [person(N2,W2)|Ps], [person(N1,W1),person(N2,W2)|Ps]) :- 
    W1  #>= W2.         % If Ps is in order, we're done! 
insertPerson(person(N1,W1), [person(N2,W2)|Ps], [person(N2,W2)|Qs]) :- 
    W1  #< W2, 
    insertPerson(person(N1,W1), Ps, Qs). 

Beispielabfrage:

 
?- sortListPerson([person(tom,65),person(dan,70),person(mike,80)], Xs). 
Xs = [person(mike,80),person(dan,70),person(tom,65)] ; 
false. 
+0

Ich habe versucht, Ihre Optimierung aber den Fehler immer noch da. Ich darf clp nicht benutzen. – Danick

+1

@Danick. Das ist schlecht. Die Verwendung von '> =' anstelle von '#> =' und '<' anstelle von '# <' im obigen Code funktioniert genauso gut. Welche Antworten bekommen * you * für die obige Abfrage '? - sortListPerson ([Person (tom, 65), Person (dan, 70), Person (mike, 80)], Xs) .' - Oder erhalten Sie einen Fehler (s) und wenn ja welche? – repeat

+0

@Danick. Müssen Sie Ihre eigene Sorte schreiben? Wenn nicht, warum nicht das eingebaute Prädikat 'keysort/2' verwenden? Es würde gut passen! – repeat

5

Der Fehler kommt von der Tatsache, dass die eingebaute in arithmetischen Operatoren wie < und =< nur auf instanzierte Bedingungen arbeiten (das heißt 1 < 2 ist wahr, aber 1 < X wirft die Ausnahme Sie erwähnt). Wenn Sie Einschränkungen verwenden, wird der Code so etwas wie:

:- use_module(library(clpfd)). 

smallest_in_rest_vars(person(N,A), [person(N,A)], [], [A]). 
smallest_in_rest_vars(person(N,A), [person(N1,A1) | Ps], % <-- this one fails without clpfd 
         [person(N1,A1) | Rs], [A1|Vs]) :- 
    A #=< A1, 
    smallest_in_rest_vars(person(N,A), Ps, Rs, Vs). 
smallest_in_rest_vars(person(N1,A1), [person(N1,A1) | Ps], 
         [person(N,A) | Rs], [A1|Vs]) :- 
    A #> A1, 
    smallest_in_rest_vars(person(N,A), Ps, Rs, Vs). 

list_sorted([],[], []). 
list_sorted(L, [Smallest|SortedRest], Vars) :- 
    smallest_in_rest_vars(Smallest, L, Rest, Vars0), 
    list_sorted(Rest, SortedRest, Vars1), 
    append(Vars0, Vars1, Vars). 

Ich nehme an, Ihr insertInPlace Prädikat smallest_in_rest_vars ähnlich ist, nur ohne die explizite Liste von Variablen Vs, die für die Kennzeichnung nützlich ist (was wir nicht brauchen, in dieser Fall). Wenn ich nicht Einschränkungen verwenden würde, würde ich die folgende Fehlermeldung erhalten, wenn ich mit Ihrer Liste abfragen:

ERROR: =</2: Arguments are not sufficiently instantiated 
    Exception: (9) smallest_in_rest_vars(_G400, [person(tom, 65), person(dan, 70), person(mike, 80)], [person(_G406, _G407)], _G462) ? 

Der Grund dafür ist, dass die Klausel, die im Beispiel markiert ist, wir wissen nichts über die neuen Person N1 noch, was zu einem Vergleich 80 < A1 führt. Ich fand mit Clpfd viel einfacher zu denken, aber wenn Sie uns Ihre insertInPlace geben, könnten wir auch eine Nicht-CLP-Lösung finden.

+0

Ja, aber wenn ** X ** und ** Y ** instanziierte Begriffe sind, die Zahlen sind, verstehe ich den Fehler nicht. Was mir komisch aussieht ist, dass die Prologperson (a, 20) die gesamte Struktur gefunden hat. Ich bin nicht erlaubt, CLP zu verwenden, danke trotzdem. – Danick

+1

Ist es möglich, dass Ihr insertInPlace nicht mit Person (N, Y) im Kopf einer Klausel vereinheitlicht, aber in den anderen es tut? –

+0

Ich habe die zwei Werte vor dem Vergleich ausgedruckt und es zeigt mir, dass sie Zahlen sind. Ich benutze 'write (Weight)' – Danick