Пролог - получение списка друзей друзей - PullRequest
0 голосов
/ 09 мая 2018

Я изо всех сил пытаюсь получить достойный результат,

У меня есть друзья,

friend(a,b).
friend(a,b2).
friend(a,b3).
friend(b,c).
friend(c,d).
friend(d,e).  
friend(e,f).

Использование findall(X,friend(a,X),List) Я получаю всех прямых друзей a

List=[b,b2,b3].

Например, я хочу получить список друзей 3 уровня a, например, я хочу прямых друзей a, друзей друзей a (это означает друзейb, b2, b3) и друзья c.Получение списка:

List=[b,b2,b3,c,d].

Я пробую все.Я могу получить только прямых друзей или всех друзей друзей.

Помощь !!

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Для предиката, который находит друзей на заданном расстоянии, как вы просили в комментариях, вам понадобятся три аргумента, то есть два друга и расстояние. Давайте дадим ему хорошее реляционное имя, скажем friend_of_maxdist/3. Теперь давайте попробуем описать отношение:

friend_of_maxdist(F1,F2,D) :-
   D > 0,                        % if the distance is greater than 0
   friend(F1,F2).                % F2 is a friend in range
friend_of_maxdist(F1,F2,D) :-
   D > 1,                        % if the distance is greater than 1
   D0 is D-1,                    
   friend(F1,X),                 % X is an intermediary friend
   friend_of_maxdist(X,F2,D0).   % of distance minus 1

Этот предикат доставляет всех друзей на заданном расстоянии один за другим:

?- friend_of_maxdist(a,F2,1).
F2 = b ;
F2 = b2 ;
F2 = b3 ;
false.

?- friend_of_maxdist(a,F2,2).
F2 = b ;
F2 = b2 ;
F2 = b3 ;
F2 = c ;
false.

?- friend_of_maxdist(a,F2,3).
F2 = b ;
F2 = b2 ;
F2 = b3 ;
F2 = c ;
F2 = d ;
false.

Теперь вы можете собрать все решения в списке. Я покажу примеры запросов с bagof / 3 , см. Ниже ниже причину, по которой:

?- bagof(F2,friend_of_maxdist(a,F2,1),L).
L = [b, b2, b3].

?- bagof(F2,friend_of_maxdist(a,F2,2),L).
L = [b, b2, b3, c].

?- bagof(F2,friend_of_maxdist(a,F2,3),L).
L = [b, b2, b3, c, d].

Однако из-за использования >/2 и is/2, friend_of_maxdist/3 выдает ошибку, если третий аргумент не является обоснованным, например, для запроса:

?- friend_of_maxdist(a,F2,N).
ERROR: >/2: Arguments are not sufficiently instantiated

Если вы не собираетесь использовать предикат таким образом, все готово. В противном случае вы могли бы взглянуть на CLP (FD) . Сделайте следующие изменения в приведенном выше коде:

:- use_module(library(clpfd)).   % <- new

friend_of_maxdist(F1,F2,D) :-
   D #> 0,                       % <- change
   friend(F1,F2).
friend_of_maxdist(F1,F2,D) :-
   D #> 1,                       % <- change
   D0 #= D-1,                    % <- change
   friend(F1,X),
   friend_of_maxdist(X,F2,D0).

Если вы попробуете проблемный запрос сейчас, вы получите ответы вместо ошибки. Тем не менее, вы получите остаточные цели (см. документация для деталей) в ответе:

?- friend_of_maxdist(a,F2,N).
F2 = b,
N in 1..sup ;
F2 = b2,
N in 1..sup ;
F2 = b3,
N in 1..sup ;
F2 = c,
N in 2..sup,
_G778+1#=N,
_G778 in 1..sup ;
F2 = d,
N in 3..sup,
_G1264+1#=N,
_G1264 in 2..sup,
_G1288+1#=_G1264,
_G1288 in 1..sup ;
F2 = e,
N in 4..sup,
_G1855+1#=N,
_G1855 in 3..sup,
_G1879+1#=_G1855,
_G1879 in 2..sup,
_G1903+1#=_G1879,
_G1903 in 1..sup ;
F2 = f,
N in 4..sup,
_G2446+1#=N,
_G2446 in 4..sup,
_G2470+1#=_G2446,
_G2470 in 3..sup,
_G2494+1#=_G2470,
_G2494 in 2..sup,
_G2518+1#=_G2494,
_G2518 in 1..sup ;
false.

Чтобы получить действительные числа вместо диапазонов для N, ограничьте его диапазон и назовите его:

?- N in 0..3, friend_of_maxdist(a,F2,N), label([N]).
N = 1,
F2 = b ;
N = 2,
F2 = b ;
N = 3,
F2 = b ;
N = 1,
F2 = b2 ;
N = 2,
F2 = b2 ;
N = 3,
F2 = b2 ;
N = 1,
F2 = b3 ;
N = 2,
F2 = b3 ;
N = 3,
F2 = b3 ;
N = 2,
F2 = c ;
N = 3,
F2 = c ;
N = 3,
F2 = d ;
false.

Теперь вы можете собирать решения, как указано выше:

?- bagof(F2,(N in 0..3, friend_of_maxdist(a,F2,N), label([N])),L).
N = 1,
L = [b, b2, b3] ;
N = 2,
L = [b, b2, b3, c] ;
N = 3,
L = [b, b2, b3, c, d].

В приведенном выше запросе вы можете увидеть, почему я предложил bagof/3 для сбора решений: N привязан к значению, а затем вы получите все решения по этому значению. Если вы попробуете то же самое с findall/3, вы получите все элементы трех списков в одном списке:

?- findall(F2,(N in 0..3, friend_of_maxdist(a,F2,N), label([N])),L).
L = [b, b, b, b2, b2, b2, b3, b3, b3|...].

Чтобы получить то же решение с bagof/3, вы должны явно указать bagof/3 не связывать N в цели:

?- bagof(F2,N^(N in 0..3, friend_of_maxdist(a,F2,N), label([N])),L).
L = [b, b, b, b2, b2, b2, b3, b3, b3|...].

Обратите внимание, что CLP (FD) -версия предиката теперь напоминает истинное отношение, как предполагает его реляционное имя.

0 голосов
/ 09 мая 2018

Следующее обозначает 3-х уровневую дружбу. Как сказано в комментариях, если вы хотите больше, вы можете искать рекурсию.

% my friend is my friend
friend_of_friend(X,Y):-
    friend(X,Y).
% the friend of my friend is my friend
friend_of_friend(X,Y):-
    friend(X,Z),
    friend(Z,Y).
% the friend of the friend of my friend is my friend
friend_of_friend(X,Y):-
    friend(X,A),
    friend(A,B),
    friend(B,Y).

Тогда

findall(X, friend_of_friend(a,X), List).

Дает:

List = [b, b2, b3, c, d]

Это будет означать бесконечную рекурсивную дружбу:

recursive_friend(X,Y):-
    friend(X,Y).
recursive_friend(X,Y):-
    friend(X,Z),
    recursive_friend(Z,Y).

И дать:

List = [b, b2, b3, c, d, e, f]
...