Ваш предикат nextking/1
довольно неэффективен и, кроме того, не гарантирует сортировку по возрасту.
Если бы мы, например, поставили charles
последним в списке фактов, мы получили бы:
?- nextking(X).
X = ann ;
X = ann ;
X = andrew ;
X = charles ;
X = charles ;
X = charles ;
X = edward.
в сущности, у того предиката, который вы написали, есть два предложения:
nextking(X) :-
age(X,P),
age(Y,Q),
P >= Q,
X\==Y.
nextking(X) :-
age(X, 55).
Первый просто даст любой X
, для которого существует человек Y
, который моложе. Но это, таким образом, не дает никаких гарантий, что эти элементы отсортированы. Наконец, последний предикат объединится со всеми людьми X
, которым 55 лет. Для этого конкретного случая это работает, но это будет означать, что если мы укажем другой факт age(louise, 14)
, то это не удастся. Подход не только неправильный, но даже если он был правильным, он будет очень «нестабильным».
Мы можем использовать предикат setof/3
[swi-doc] , который не только выполняет фильтр уникальности, но и сортирует элементы.
Так как мы хотим отсортировать членов королевской семьи по возрастанию, мы должны построить 2 кортежа (или другую структуру, которая объединяет два параметра), где первый параметр содержит отрицательный возраст , а второй параметр соответствующий человек.
Затем мы можем использовать member/2
[swi-doc] , чтобы «раскрутить» список в отдельных единицах:
nextking(X) :-
setof((NA, X), A^(age(X, A), NA is -A), Royals),
member((_, X), Royals).
Будет создан список элементов, таких как:
?- nextking(X).
X = charles ;
X = ann ;
X = andrew ;
X = edward.
независимо от того, как упорядочены факты в исходном файле.