1. 程式人生 > >Prolog教程 7-舉一個分析家譜的程式

Prolog教程 7-舉一個分析家譜的程式

到現在為止,我們已經對Prolog有了一個基本的瞭解,現在有必要對我們所學過的知識做一個系統的總結。

Prolog的程式是由一系列的事實和規則組成的資料庫。
規則之間的呼叫是通過聯合操作完成的,Prolog能夠自動的完成模式匹配。
規則還可以呼叫內部謂詞,例如write/1。
我們可以在Prolog的直譯器中單獨地對規則進行查詢(呼叫)。

在Prolog的程式的執行流程方面我有了如下的認識:

規則的執行是通過Prolog內建的回溯功能實現的。
我們可以使用內部謂詞fail來強制實現回溯。
我們也可以通過加入一條引數為偽變數(下劃線)無Body部分的子句,來實現強制讓謂詞成功。

我們還學習了,

資料庫中的事實代替了一般語言中的資料結構。
回溯功能能夠完成一般語言中的迴圈操作。
而通過模式匹配能夠完成一般語言中的判斷操作。
規則能夠被單獨地除錯,它和一般語言中的模組相對應。
而規則之間的呼叫和一般語言中的函式的呼叫類似。

有了以上的知識,我們還可以編寫出一些讓其它語言的程式設計師吃驚的小程式。下面就舉一個分析家譜的程式。

假如我們把家族成員之間的父子關係和夫妻關係,以及成員的性別屬性定義為基本的事實資料庫,我們就可以編出許多規則來判斷其他的親戚關係了。

例如我們有如下的資料庫:

father(a,b).
father(a,d).
father(a,t).
father(b,c).

wife(aw,a).
wife(bw,b).

male(t).
female(d).
male©.

father(a,b).表示a是b的父親。
wife(aw,a). 表示aw是a的妻子。
male(t).表示b是男性。
female(d).表示d是女性。

上面我們並沒有定義a、b、aw、bw的性別。 因為通過他們和其他人的關係我們可以很容易地確定他們的性別。不過要想讓Prolog知道他們的性別我們就要定義如下的規則。

male(X):-father(X,).
female(X):-wife(X,
).

上面的male/1和female/1的謂詞名稱和事實的名稱相同,這並不是什麼特別的情況,你可以把所有定義相同的謂詞的子句之間的關係想象“或者”的關係。也就是說:t和d是男性,或者如果X是其他人的父親,則它也是男性。在判斷性別時,我們並不關心此人是誰的父親,所以後面一個變數用“_”代替了。

好了,假如有如下的詢問:

?-male(t).
yes.

?-male(a).
yes.

?-male(X).
X=t;
X=c;
X=a;
X=a;
X=a;
X=b;
no.

最後一個詢問,它雖然把所有的男性找了出來,可是它把a找了三次,原因很簡單,因為我們有三個father/2的子句都包含a,好像不太理想,不過現在只能將就一下了,當我們學習了更多的知識後,就好解決了。

下面我們定義一些其他的親戚關係的規則。你大概一看就能夠理解。例如:X和Y是兄弟的條件是: X和Y有相同的父親{father(Z,X),father(Z,Y)},並且他們都是男性{male(X),male(Y)},最後由於X和Y可以取相同的值,所以我們不得不加上一條X和Y不是同一個人{X/=Y}。

grandfather(X,Y):-father(X,Z),father(Z,Y).
mother(X,Y):-wife(X,Z),father(Z,Y).
brother(X,Y):-father(Z,X),father(Z,Y),male(X),male(Y),X/=Y.

當然我們還可以加入更復雜一點的規則,

uncle(X,Y):-brother(X,Z),father(Z,Y).

這個叔伯的規則uncle/2呼叫了前面的規則brother/2。

這裡只是簡單回顧一下前面所學習的知識,所以這個家族程式雖然可以使用,但是卻極不完善。例如:它會把某一答案重複多次,還不能描述沒有小孩的丈夫的性別。 我們這樣改一下會更好一點:male(X):-wife(_,X)。因此,規則的定義是多種多樣的,到底哪種更好、哪種更快,這就是我們以後所要研究的問題之一了。