Пролог: устранение циклов из косвенного отношения

У меня есть список пользовательских фактов, определенных как:

user(@michael).
user(@ana).
user(@bob).
user(@george).
user(@john).

и так далее. Кроме того, у меня есть ряд фактов:

follows(@michael,@ana).
follows(@ana,@bob).
follows(@bob,@michael).

Я пытаюсь написать косвенное отношение (user1,user1), которое скажет мне, если user1 косвенно следует за user2. Однако я не могу покончить с циклическими отношениями.

Как и в данном примере, michael -> ana -> bob -> michael вызовет цикл.

Каков наилучший способ устранить эти циклы из косвенного (user1,user2)?

2 ответа

Решение

Вы можете создать правило, которое передает дополнительный список пользователей, которых вы "видели" до сих пор, и игнорировать последующие, исходящие от этих пользователей: follows(A, B, Seen),

Чтобы сделать это, определите правило "следовать транзитивному", которое обертывает фактическое правило, например так:

follows_tx(A, B) :- follows(A, B, []).

Теперь вы можете определить follows/3 править таким образом:

follows(A, B, Seen) :-
    not_member(B, Seen),
    follows(A, B).
follows(A, B, Seen) :-
    follows(A, X),
    not_member(X, Seen),
    follows(X, B, [A|Seen]).

Базовый пункт говорит, что если есть факт о A следующий Bмы считаем предикат проверенным до тех пор, пока мы не видели B до.

В противном случае мы найдем кого-то, кто следует Aпроверьте, что мы еще не видели этого пользователя, проверив not_member/2и, наконец, посмотреть, следует ли этот пользователь Bпрямо или косвенно.

Наконец, вот как вы можете определить not_member:

not_member(_, []).
not_member(X, [H|T]) :- dif(X, H), not_member(X, T).

Demo.

indirect( A0,A) :-
   closure(follows, A0,A).

Смотрите для определения closure/3,

Другие вопросы по тегам