我在prolog中有这个程序,我基本上定义了一个人的图表,我需要制作一些谓词,告诉我哪些人是连接的,哪些是派系。以下是事实:
graph([person(susan, [reed, jen, andrzej, jessica]),
person(reed, [tony, jessica]),
person(jessica, [jen,susan]),
person(tony, []),
person(ken, [andrzej]),
person(jen, [tony, susan, jessica]),
person(andrzej, [susan, ken])]).
这是我的谓词clique的定义。它将图G和人员列表作为参数,并尝试检查列表中的人是否确实是一群朋友。(这意味着谓词好朋友对于列表中的每对人都是如此)
clique(G, [FriendOne, FriendTwo]):-
goodfriends(G, FriendOne, FriendTwo).
clique(G, [FriendOne | FriendList]):-
atLeastTwoElements(FriendList),
clique(G, FriendList),
goodFriendWith(G, FriendOne, FriendList).
集团的作用是:如果列表中只有两个人,那么只要检查这两个人是否是好朋友。如果这是真的那么他们两个之间就有一个集团。如果人员列表中有两个以上的人,那么列表的每个负责人,即人员检查他是否是列表尾部其余人员的好朋友,并递归地为所有列表人。 下面定义了clique工作的其余辅助谓词。
goodfriends(G, FriendOne, FriendTwo):-
getPerson(G, FriendOne, PersonOne),
getPerson(G, FriendTwo, PersonTwo),
hasFriend(PersonOne, FriendTwo),
hasFriend(PersonTwo, FriendOne).
%% checks if this friend is goodfriend with all these friends
goodFriendWith(_, _, []).
goodFriendWith(G, FriendOne, [FriendTwo | FriendList]):-
goodFriendWith(G, FriendOne, FriendList),
goodfriends(G, FriendOne, FriendTwo).
%% gets specific person by a name from the graph
getPerson([person(Name, Friends)|_], Name, person(Name, Friends)).
getPerson([_|T], Name, Result):-
getPerson(T, Name, Result).
%% checks if a person has a certain friend
hasFriend(person(_, Friends), Friend):-
member_(Friend, Friends).
member_(X, [X|_]).
member_(X, [_|Tail]) :- member_(X, Tail).
atLeastOneElement([_|_]).
atLeastTwoElements([_,_|_]).
当我创建名为runner的谓词来测试谓词“clique”时:
runner(R):-
graph(G),
clique(G, R).
我想让它返回图表中的所有派系,但结果是:
?- runner(R).
R = [susan, jessica] ;
R = [susan, jen] ;
R = [susan, andrzej] ;
R = [jessica, susan] ;
R = [jessica, jen] ;
R = [ken, andrzej] ;
R = [jen, susan] ;
R = [jen, jessica] ;
R = [andrzej, susan] ;
R = [andrzej, ken] ;
R = [jen, susan, jessica] ;
R = [jessica, susan, jen] ;
R = [jen, jessica, susan] ;
R = [susan, jessica, jen] ;
R = [jessica, jen, susan] ;
R = [susan, jen, jessica] ;
ERROR: Out of local stack
递归有什么问题?我知道我得到了正确的结果,但由于某种原因,所有结果都显示出它不断递归。
提前谢谢。
答案 0 :(得分:3)
在像你这样的纯粹单调程序中有一种简单的调试技术。只需将 false
目标添加到您的计划中即可。如果生成的程序仍然循环,则必须修复剩余的可见部分。 (可能存在更多错误,但只要该部分未修复,您将无法解决问题)
这是我到目前为止所得到的:
runner(R):- graph(G), clique(G, R), false.clique(G, [FriendOne, FriendTwo]):- false,goodfriends(G, FriendOne, FriendTwo).clique(G, [FriendOne | FriendList]):- atLeastTwoElements(FriendList), goodFriendWith(G, FriendOne, FriendList), false,clique(G, FriendList).
因此,goodFriendWith
中存在一个或一个问题。我发现你的定义对于无限多的列表来说是成功的,这有点令人恼火:
?- length(L,N),
maplist(=(jessica),L),
goodFriendWith(
[ person(susan,[reed,jen,andrzej,jessica]),
person(reed,[tony,jessica]),
person(jessica,[jen,susan]),
person(tony,[]),
person(ken,[andrzej]),
person(jen,[tony,susan,jessica]),
person(andrzej,[susan,ken])],
susan,
L).
L = [],
N = 0 ;
L = [jessica],
N = 1 ;
L = [jessica, jessica],
N = 2 ;
L = [jessica, jessica, jessica],
N = 3 ;
L = [jessica, jessica, jessica, jessica],
N = 4 ;
L = [jessica, jessica, jessica, jessica, jessica],
N = 5 ...
因此,对于仅仅两个人来说,已经存在无限的不同解决方案。那不能终止!你需要解决这个问题。
或者,更准确地说:
?- goodFriendWith([person(susan,[jessica]),person(jessica,[susan])],susan,L).
L = [] ;
L = [jessica] ;
L = [jessica, jessica] ;
L = [jessica, jessica, jessica] ;
L = [jessica, jessica, jessica, jessica] ;
L = [jessica, jessica, jessica, jessica, jessica]
这个目标必须产生有限的许多解决方案。但是,有无数的。
由于您对结果感到惊讶,让我们继续调试。为了使其更加明显,我现在将添加额外的目标(=)/2
。这些目标也将专门化该计划:
goodFriendWith(_, _, []) :- false.goodFriendWith(G, FriendOne, [FriendTwo | FriendList]):- FriendOne = susan, FriendTwo = jessica, goodfriends(G, FriendOne, FriendTwo), goodFriendWith(G, FriendOne, FriendList), false. ?- goodFriendWith([person(susan,[jessica]),person(jessica,[susan])],susan,L).
再次,查询循环!你现在真的应该看到问题了。