2

我在序言中有这个程序,我基本上定义了一个人的图表,我需要做一些谓词来告诉我哪些人是有联系的,哪些是派系。以下是事实:

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 和人员列表作为参数,并尝试检查列表中的人是否确实是朋友圈。(这意味着谓词 goodfriends 对于列表中的每一对人都是正确的)

clique(G, [FriendOne, FriendTwo]):-
  goodfriends(G, FriendOne, FriendTwo).
clique(G, [FriendOne | FriendList]):-
  atLeastTwoElements(FriendList),
  clique(G, FriendList),
  goodFriendWith(G, FriendOne, FriendList).

clique 所做的是:如果列表仅包含两个人,则只需检查这两个人是否是好朋友。如果这是真的,那么他们两个之间就有一个派系。如果人员列表中有两个以上的人,那么对于列表的每个头部,即人员检查他是否与列表尾部的其余人员是好朋友,并递归地对所有列表执行此操作人。下面定义了 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

递归有什么问题?我知道我得到了正确的结果,但出于某种原因,所有结果都显示它不断递归。

先感谢您。

4

1 回答 1

3

在像您这样的纯单调程序中有一种简单的调试技术。只需将false目标添加到您的计划中。如果生成的程序仍然循环,则必须修复剩余的可见部分。(可能会有更多错误,但只要那部分没有修复,你就不会修复问题)

这是我到目前为止得到的:

亚军(R):-
  图(G),
  集团(G,R),clique(G, [FriendOne, FriendTwo]):- false , 
  goodfriends(G, FriendOne, FriendTwo)。
集团(G,[FriendOne | FriendList]):-
  atLeastTwoElements(朋友列表),
  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 = 苏珊FriendTwo = 杰西卡,
  好朋友(G,FriendOne,FriendTwo),
  goodFriendWith(G, FriendOne, FriendList), false。

?- goodFriendWith([person(susan,[jessica]),person(jessica,[susan])],susan,L)。

再次,查询循环!你现在真的应该看到问题了。

于 2014-09-27T15:26:05.310 回答