族谱数据库
在这一节我们通过一个族谱数据库来介绍prolog编程,我们将通过这个族谱数据库获得家庭成员间的基本关系。在
这个程序里我们将示范怎样使用prolog中的事实、规则、变量和递归。
首先我们通过prolog中的事实表示一个人具有男人或女人这样的属性:
man(adam).
man(peter).
man(paul).
woman(marry).
woman(eve).
然后我们添加parent关系,它由双亲和孩子组成:
parent(adam,peter). % means adam is parent of peter
parent(eve,peter).
parent(adam,paul).
parent(marry,paul).
直到现在我们还仅仅添加的是事实,但在prolog编程中它最强有力的表达方式是规则。事实表达的是清楚明确的关
系,规则定义的是关系的更普遍的一种情况。每一个规则都包含一个头和主体,头定义的是关系名称,主体是关系的定
义。下面的这些规则定义了父亲和母亲关系,并使用了之前定义的男人、女人和双亲关系。
father(F,C):-man(F),parent(F,C).
mother(M,C):-woman(M),parent(M,C).
我们通过变量来表示每个男人是他的孩子的父亲这样一个规则,需要注意在prolog中首字母是大写的字符串表示变量。
如果某个参数在关系中并不是很重要的我们可以使用匿名参数(用“_“表示),例如:
is_father(F):-father(F,_).
is_mother(M):-mother(M,_).
在我们继续下面的内容前我们需要知道怎样运行prolog程序。你可以通过提出问题来运行程序:
?-father(X,paul).
这个表示谁是paul的父亲?回答是adam。
现在我们来扩展一下数据库,添加一些新的家庭关系,比如儿子、阿姨、祖父母,试着向prolog系统提出不同的问题
看看会有怎样的反应。你可以给你的程序添加下面的这些规则:
son(S,P):-man(S),parent(P,S).
daughter(D,P):-woman(D),parent(P,D).
siblings(A,B):-parent(P,A),parent(P,B),A\=B.
% siblings have at least one common parent
% the test A\=B preserves that siblings are different persons
full_siblings(A,B):-
parent(F,A),parent(F,B),
parent(M,A),parent(M,B),
A\=B, F\=M.
% full siblings have common parents (both)
% the test F\=M preserves that full siblings have two different parents (father and mother, naturally)
full_siblings2(A,B):-
father(F,A),father(F,B),
mother(M,A),mother(M,B),
A\=B.
% another solution to "full siblings problem" that uses relations father and mother
uncle(U,N):-man(U),siblings(U,P),parent(P,N).
aunt(A,N):-woman(A),siblings(A,P),parent(P,N).
grand_parent(G,N):-parent(G,X),parent(X,N).
直到现在我们还仅仅用一条规则表示一个关系,实际上我们可以使用两条或更多条规则去表示一个关系。如果我们希望
表示人类就是男人或女人这样一个关系,我们可以使用两条规则这样定义:
human(H):-man(H).
human(H):-woman(H).
在规则的主体部分也可以使用正在定义的关系,这种定义方式称为递归定义。一个典型的递归定义如下所示:
descendent(D,A):-parent(A,D).
descendent(D,A):-parent(P,D),descendent(P,A).
我们可以使用prolog不要定义输入输出变量的功能轻松的定义祖先关系:
ancestor(A,D):-descendent(D,A).