2016-05-10 3 views
1

Я пытался отсортировать список структуры.Prolog Сортировка списка структуры, арифметическая ошибка

Структура как этот

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

И этот список будет как этого

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

Я хочу, чтобы отсортировать список из наибольшего веса как минимум. Как это:

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

До сих пор у меня есть это:

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). 

Я пытался со списком из двух людей, и она работает:

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

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

Но когда я пытаюсь с в списке 3 или более человек появляется сообщение об ошибке:

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

no 
?- 

Может ли кто-нибудь помочь?

+1

Вы на самом деле не 'лицо (Имя , Вес) .' написано как факт, не так ли? – lurker

+2

Я не вижу '> =/2', используемого в любом месте кода, который вы показываете, но ошибка явно относится к этому оператору. Возможно, в вашем предикате 'insertInPlace/3' есть проблема, которая не отображается. – lurker

+1

@ Danick: Есть ли причина, по которой вы отредактировали тег [tag: clpfd]? Это кажется актуальным для вашего вопроса; http://stackoverflow.com/tags/clpfd/info. – Matt

ответ

5

Как я вижу это ваша вставка сортировки в порядке, во второй статье о 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). 

Пример запроса:

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

Я пробовал вашу оптимизацию, но ошибка все еще там. Мне не разрешено использовать clp. – Danick

+1

@ Даник. Плохо. Использование '> =' вместо '#> =' и '<' вместо '# <' в приведенном выше коде также работает. Какие ответы вы делаете * вы * получаете для вышеуказанного запроса '? - sortListPerson ([person (tom, 65), person (dan, 70), person (mike, 80)], Xs) .' - или вы получаете ошибку (s) и если да, то какие? – repeat

+0

@ Danick. Вам нужно написать свой собственный вид? Если нет, почему бы не использовать встроенный предикат 'keysort/2'? Это будет хорошо! – repeat

5

ошибка исходит из того, что встроенные арифметические операторы, такие как < и =< работают только на конкретизированных условиях (т.е. 1 < 2 верно, но 1 < X бросает исключение, вы упомянули). Если вы используете ограничения, код становится чем-то вроде:

:- 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). 

Я полагаю, ваш insertInPlace предикат подобен smallest_in_rest_vars, только без явного списка переменных Vs, который полезен для маркировки (который нам не нужен в этом дело). Если бы я не использовать ограничение, я получаю следующее сообщение об ошибке, когда я запрос со списком:

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) ? 

Причина заключается в том, что положение, которое отмечается в этом примере, мы ничего не о новом знать человек N1, что приводит к сравнению 80 < A1. Я обнаружил, что использование clpfd гораздо проще, но когда вы дадите нам свой insertInPlace, мы можем найти решение, отличное от clp.

+0

Да, но если ** X ** и ** Y ** являются экземплярами, которые являются числами, я не понимаю ошибку. То, что выглядит странно для меня, - это то, что пролог обнаружил человека (а, 20) всю структуру. Я не позволю использовать CLP, спасибо в любом случае. – Danick

+1

Возможно ли, что ваш insertInPlace не объединяется с человеком (N, Y) в голове одного предложения, а в других случаях? –

+0

Я уже напечатал два значения, прежде чем сравнивать их, и это показывает мне, что они являются числами. Я использую 'write (Weight)' – Danick

Смежные вопросы