Prolog : eliminating cycles from indirect relation

戏子无情 提交于 2020-01-04 06:21:06

问题


I have a list of user facts defined as:

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

and so on. Furthermore, I have a set of facts as:

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

I am trying to write a relation indirect(user1,user1) which will tell me if user1 indirectly follows user2. However, I am not able to do away with cyclic relations.

Like in the given example, michael -> ana -> bob -> michael will cause a cycle.

What is the best way to eliminate these cycles from the result of indirect(user1,user2)?


回答1:


You can make a rule that passes an extra list of users that you have "seen" so far, and ignore follows originating from these users: follows(A, B, Seen).

To do that, define a "follow transitive" rule that wraps the actual rule, like this:

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

Now you can define follows/3 rule this way:

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]).

The base clause says that if there is a fact about A following B, we consider the predicate proven as long as we have not seen B before.

Otherwise, we find someone who follows A, check that we have not seen that user yet by checking not_member/2, and finally see if that user follows B, directly or indirectly.

Finally, here is how you can define not_member:

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

Demo.




回答2:


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

See for a definition of closure/3.



来源:https://stackoverflow.com/questions/27258188/prolog-eliminating-cycles-from-indirect-relation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!