Пролог: устранение циклов из косвенного отношения
У меня есть список пользовательских фактов, определенных как:
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
,