在Prolog中只匹配数据库项一次?

时间:2013-02-25 19:56:08

标签: prolog

让我们说Prolog中有一个简单的人员数据库

person(john).
person(mary).    
person(john).
person(susan).

我需要恰好匹配entires一次:

john-mary, john-john, john-susan, mary-john, mary-susan, john-susan

我尝试过这样的事情:

match:- person(X),!,person(Y),   write(X),write(-), write(Y),nl.
run:- person(X), match(X), fail.

但它匹配了很多次,并且将一个人与他/她相匹配,这不应该是。

基本上,我需要的是迭代所有X并让Prolog严格看待"低于"对于Ys。

2 个答案:

答案 0 :(得分:2)

快速解决方案是为您的员工编号:

person(1, john).
person(2, mary).
person(3, john).
person(4, susan).

然后你可以匹配这样的人:

match(X-Y) :-
  person(I, X), person(J, Y), I < J.

由于您有两个john条目,我不确定任何其他解决方案是否可行。通常你可以使用@>/2伪造一个排序,但这需要你的原子是唯一的,因为它们不是,它会阻止john-john解决方案。

修改:由于我们愿意使用findall/3来实现人员数据库,因此我们可以将其视为列表问题并找到功能性解决方案。让我们在列表中获得所有组合:

combinations([X|Rest], X, Y) :- member(Y, Rest).
combinations([_|Rest], X, Y) :- combinations(Rest, X, Y).

有了这个谓词,我们可以找到解决方案:

combined_folks(People) :-
  findall(P, person(P), Persons),
  findall(X-Y, combinations(Persons, X, Y), People).

?- combined_folks(X).
X = [john-mary, john-john, john-susan, mary-john, mary-susan, john-susan].

实际上结果很干净!

答案 1 :(得分:1)

person(john).
person(mary).    
person(john).
person(susan).    

match :- findall(P,person(P),People), match_all(People).

match_all([_]) :- !.
match_all([P|People]) :- match_2(P,People), match_all(People).

match_2(_,[]) :- !.
match_2(P1,[P2|People]) :- format('~a-~a~n',[P1,P2]), match_2(P1,People).

?- match.