Как не показать, если один и тот же результат встречается более одного раза - Пролог - PullRequest
0 голосов
/ 31 октября 2018

Сценарий

У меня есть код, как показано ниже. У меня вопрос, как не показывать один и тот же результат более одного раза.

male(charles).
male(andrew).
male(edward).

female(ann).

age(charles, 70).
age(ann, 65).
age(andrew, 60).
age(edward, 55). 

nextking(X) :- age(X,P), age(Y,Q),
               P>=Q, X\==Y;  age(X,55).

Токовый выход

enter image description here

Что мне нужно

Мне нужны выходные данные Чарльза, Энн, Эндрю, Эдварда. Нет повторения имен.

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Ваш предикат 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. 

независимо от того, как упорядочены факты в исходном файле.

0 голосов
/ 31 октября 2018

С довольно свежей версией вы можете использовать библиотеку ( solution_sequence ):

?- distinct(nextking(X)).
X = charles ;
X = ann ;
X = andrew ;
X = edward.

или используйте встроенную классическую «все решения»:

?- setof(K,K^nextking(K),Ks),member(X,Ks).
Ks = [andrew, ann, charles, edward],
X = andrew ;
Ks = [andrew, ann, charles, edward],
X = ann ;
...

но в этом случае мы теряем порядок ответов, определенный в КБ.

...