0

假设 Prolog 中有一个简单的人员数据库

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

我需要完全匹配一次:

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 看起来严格“低于”Y。

4

2 回答 2

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

结果发现真的很干净!

于 2013-02-25T20:27:13.713 回答
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.
于 2013-02-25T20:59:13.057 回答