失败和回溯的问题

时间:2015-04-27 03:42:55

标签: prolog

我正在制定一项计划,测试一个人是否可以成为公民。当数据库中的某个人被传入时,它应该返回他们做或不符合的所有原因。我的问题是,为了显示所有原因,我使用了无法回溯并找到其他原因,这使得返回false应该是真的。

born(frank,usa,1944). 
child(frank,mary,jack).
child(mary,sean,ruth).
born(fiona,usa,1920).
child(fiona,sean,ruth).

citizen(X):- born(X,'irl',_).
natcitizen(X):-naturalized(X,_). 
marriedirl(X):-married(X,Y,_),born(Y,'irl',_).
adoptedirl(X):-adopted(X,P1,P2),born(P1,'irl',_),born(P2,'irl',_).
irlparent(X):-child(X,P1,P2),(born(P1,'irl',_);born(P2,'irl',_)).
irlgrandparent(X):- child(X,P1,P2),(child(P1,G1,G2),(born(G1,'irl',_);born(G2,'irl',_));child(P2,G3,G4),(born(G3,'irl',_);born(G4,'irl',_))).
permres5(X):-(permres(X,Start,End),born(X,_,B),A is B, 2015-A@>=18,End==2015,N is End-Start,(N@>=5)).


qualify(X):- \+(citizen(X) ->write(X) ->write_ln( ' is already an irish born citizen')), \+ (natcitizen(X)  ->write(X) ->write( ' is already a naturalized Irish citizen')),
(marriedirl(X)->write(X) ->write_ln(' qualifies: he/she is married to an Irish citizen'));
(adoptedirl(X))->write(X) ->write_ln(' qualifies: he/she was adopted by Irish-born parents');
(irlparent(X)->write(X) ->write_ln(' qualifies: he/she has an Irish parent')),fail;
(irlgrandparent(X) ->write(X) ->write_ln(' qualifies: he/she has an Irish grandparent')),fail;
(permres5(X) ->write(X) ->write_ln(' qualifies: he/she is an Irish permanent resident and has been for at least 5 years')),fail.

所以当fiona被召唤时: 菲奥娜有资格:他/她有一个爱尔兰父母 假。 返回而不是真。

坦白说: 弗兰克有资格:他/她有一个爱尔兰父母 弗兰克有资格:他/她有一个爱尔兰祖父母 假的。

它应该说是真的,我不确定如何在不改变失败的情况下改变真值,并打破回溯。

整个代码的pastebin:http://pastebin.com/tp7Mi5s6

1 个答案:

答案 0 :(得分:1)

您用来强制枚举所有解决方案的方法称为"故障驱动循环"。

setof/3这样的全解决方案谓词可能更适合您的需求。

首先,我将qualify/1替换为person_qualified_reason/3

person_qualified_reason(P,Decision,Reason) :-
   citizen(P),
   !,
   Decision = no,
   Reason   = 'already an irish born citizen'.
person_qualified_reason(P,Decision,Reason) :-
   natcitizen(P),
   !,
   Decision = no,
   Reason   = 'already a naturalized Irish citizen'.
person_qualified_reason(P,yes,'married to an Irish citizen') :-
   marriedirl(P).
person_qualified_reason(P,yes,'adopted by Irish-born parents') :-
   adoptedirl(P).
person_qualified_reason(P,yes,'has an Irish parent') :-
   irlparent(P).
person_qualified_reason(P,yes,'has an Irish grandparent') :-
   irlgrandparent(P).
person_qualified_reason(P,yes,'has been Irish permanent resident for 5+ years') :-
   permres5(P).

示例查询:

?- person_qualified_reason(frank,D,Reason).
D = yes, Reason = 'has an Irish parent' ;
D = yes, Reason = 'has an Irish parent' ;            % redundant answer
D = yes, Reason = 'has an Irish grandparent' ;
D = yes, Reason = 'has an Irish grandparent' ;       % redundant answer
false.

要收集所有原因,我们可以使用内置setof/3

?- setof(Decision-Reason,person_qualified_reason(frank,Decision,Reason),All).
All = [yes-'has an Irish grandparent', yes-'has an Irish parent'].

knownPerson/1适用于数据库中已知的所有人员:

knownPerson(X) :- adopted(X,_,_).
knownPerson(X) :- adopted(_,X,_).
knownPerson(X) :- adopted(_,_,X).
knownPerson(X) :- naturalized(X,_).
knownPerson(X) :- permres(X,_,_).
knownPerson(X) :- child(X,_,_).
knownPerson(X) :- child(_,X,_).
knownPerson(X) :- child(_,_,X).
knownPerson(X) :- married(X,_,_).
knownPerson(X) :- married(_,X,_).
knownPerson(X) :- born(X,_,_).

为了摆脱knownPerson/1的冗余答案,我们定义了一个辅助谓词:

person(X) :- setof(t,knownPerson(X),_).

最后,让我们看看谁有资格,谁没有,以及出于哪些原因。我把你在pastebin链接中提供的数据拿走了:

?- person(P),
   setof(Q-Reason,person_qualified_reason(P,Q,Reason),Verdict).
P = aisling, Verdict = [yes-'has an Irish grandparent']           ;
P = andy,    Verdict = [no-'already a naturalized Irish citizen'] ;
P = anna,    Verdict = [yes-'has an Irish grandparent']           ;
P = brendan, Verdict = [no-'already an irish born citizen']       ;
P = bridgen, Verdict = [no-'already an irish born citizen']       ;
P = bridget, Verdict = [yes-'has an Irish parent'] ...