Learn Prolog Now!第一章 入門

1.1 一些簡單案例

Prolog裏只有三個基本的構建單元:事實,規則,查詢( facts, rules, queries )。事實和規則的集合叫做知識庫(或者叫數據庫) 。Prolog編程就是寫知識庫,就是用事實和規則來描述一些有趣的關係。

那麼,我們怎麼用Prolog編程?

——查詢。就是要靠提問,問那些存儲在知識庫裏的信息。

這可能聽起來很玄。這看起來與編程不相干,畢竟,編程不是要告訴計算機怎麼做麼,如此一來不是本末倒置? 但以後我們會發現,Prolog的編程方式是很有用的(至少對於特定領域是的)。比如對計算機語言學,人工智能。

不講了,讓我們馬上開始動手寫一些簡單的知識庫。動手不是學習Prolog的最好方法,而是唯一的方法。

譯者有話說!!!

原文沒有講怎麼運行腳本,新手可能有點懵,所以我來補充一下。

翻譯的時候我會對原文進行適當的改動,或者補充,能讓讀者更好的理解。覺得難懂拗口的地方大可跳過,先看後面,大部分不影響理解。

我安裝的是GNU Prolog。


知識庫文件寫好了保存爲 XXXX.pl

雙擊就可以運行,編譯了。

然後查詢語句在 | ?- 後面輸(結尾記得句號!!!!!!)

其他系統,或者裝其他版本,就自己找資料吧。教程的實例以GNU Prolog爲準。

知識庫1

知識庫1(KB1.pl)裏有五個事實。事實,顧名思義。

比如,我們可以用以下五條事實來聲明" Mia、Jody、Yolanda是女人,Jody彈空氣吉他,這裏在開派對 "

woman(mia). 
woman(jody). 
woman(yolanda). 
playsAirGuitar(jody). 
party.

這就是KB1。我們第一個Prolog程序。請注意她們的名字 ”Mia、Jody、Yolanda“,還有她們的屬性woman 和 playsAirGuitar ,以及party。一定注意都用小寫,稍後我會講原因的。

那KB1怎麼用?靠問(查詢)。就是問KB1所包含的信息。這有一些例子,我們可以用這種方法問Prolog,Mia是不是女人:

?-  woman(mia).

yes

結果很顯然,因爲這是KB1中的一條事實。對了,|?-不用自己打,這是prolog的命令提示符。我們只需要在後面鍵入我們的查詢即可(比如woman(mia))。切記,結尾要加句號(英文句號),否則prolog不會運行。

同樣,我們可以這樣查詢 Jody是否彈空氣吉他。:

?-  playsAirGuitar(jody).
 
yes

讓我們查詢一下Mia是否彈空氣吉他。:

?-  playsAirGuitar(mia).

no

答案顯然,因爲這並不是KB1裏面的事實。

來分析兩個例子。第一個,假如我們發出以下查詢:

?-  playsAirGuitar(vincent).

prolog肯定會回答no。爲什麼?查詢的人Vincent不存在,沒有任何與他有關的信息。所以, playsAirGuitar(vincent) 無法由KB1得出,結果正確。

類似的,我們再發出以下查詢:

?-  tatooed(jody).

prolog仍會回答no。爲什麼?因爲該查詢的屬性(謂詞)tatooed知識庫裏沒有,KB1再一次給出否定的答案(其實,再有些版本的prolog裏,這樣的情況會報錯。它會告訴你tatooed的謂詞(predicate)或者叫過程(procedure)沒有定義。我們馬上會介紹謂詞的概念。)

下面例子的結果毋庸置疑:

?-  party.

yes
?-  rockConcert.

no

知識庫2

看第二個知識庫(KB2):

happy(yolanda). 
listens2Music(mia). 
listens2Music(yolanda):-  happy(yolanda). 
playsAirGuitar(mia):-  listens2Music(mia). 
playsAirGuitar(yolanda):-  listens2Music(yolanda).

KB2裏有兩條事實和三條規則,後三行就是規則。

規則就是某物只有在某條件下才成立的信息。比如,第一條規則就是,如果Yolanda開心,她就會聽歌。比如最後一條,如果Yolanda聽歌,她就會彈空氣吉他。概括來講 ” :- “ 符號可以讀成”如果“:-符號左邊的稱爲規則的頭部,右邊被稱爲規則的主體。再概括一下:如果規則的主體爲真,則其頭部也爲真。

上述內容就能被稱爲演繹推理(modus ponens)。

讓我們來考慮這個例子:

?-  playsAirGuitar(mia).

yes

因爲KB2中有 playsAirGuitar(mia):- listens2Music(mia)這個規則 和listens2Music(mia)這個事實,所以可以得出正確的推論。

下面的例子展示了串聯的使用演繹推論

?-  playsAirGuitar(yolanda).

yes

答案很容易,我們通過下面的規則和事實可以推導出正確答案:

playsAirGuitar(yolanda):-  listens2Music(yolanda).
到
listens2Music(yolanda):-  happy(yolanda). 
到
happy(yolanda). 

小結:任何被推導出來的事實也是事實。串聯一些演繹推論,prolog會更強大。

知識庫裏的事實和規則被稱爲子句。KB2有五條子句(三個規則和兩個事實)。KB2有如下三個謂詞:

listens2Music 
happy 
playsAirGuitar

謂詞“happy”由一個子句(事實)定義。listens2Music 和 playsAirGuitar 分別由兩個謂詞定義(第一個用了兩條規則,第二個用了一條規則和一條事實)。通過謂詞來考慮程序是一個好主意。本質上,謂詞就是我們覺得重要的概念。我們寫下他們的子句,是爲了確定他們的含義和他們之間的關係。

最後一點。我們可以把事實看作一條沒有規則主體的規則。就是一個在任何情況下條件都能成立的規則。

知識庫3

KB3,我們的第三個知識庫,由五個子句(兩條事實和三條規則)組成:

happy(vincent). 
listens2Music(butch). 
playsAirGuitar(vincent):- 
    listens2Music(vincent), 
    happy(vincent). 
playsAirGuitar(butch):- 
    happy(butch). 
playsAirGuitar(butch):- 
    listens2Music(butch).

KB3用了和KB2一樣的謂詞(happy ,listens2Music , 和 playsAirGuitar),但是也有不同,這三條規則給 playsAirGuitar 引入了一些新的含義。注意這個規則:

playsAirGuitar(vincent):- 
    listens2Music(vincent), 
    happy(vincent).

規則主體裏有兩個項目,或者用術語來說,有兩個目標(goals)。這個規則到底是什麼意思呢?千萬要注意這個逗號,用來分隔不同的目標。這就是prolog的邏輯連接方式(逗號可以讀作並且,也就是)。所以這個規則可以讀作:“Vincent 會彈空氣吉他,如果他聽音樂並且他很快樂)。

因此,如果我們查詢:

?-  playsAirGuitar(vincent).

prolog會回答 no 。因爲雖然KB3包含了happy(vincent),但是無法得出listens2Music(vincent)。所以KB3只滿足了使playsAirGuitar(vincent)成立的兩個條件中的一個。所以回答了no。

順便一提,規則中的空格沒有影響。比如,我們完全可以把上面那個規則寫成:

playsAirGuitar(vincent):-  happy(vincent), 
                                     listens2Music(vincent).

prolog在知識庫的排版上給了我們很大的自由,所以我們可以以此來保持我們代碼的可讀性。

接下來,注意KB3包含了兩條有同樣頭部的規則:

playsAirGuitar(butch):- 
    happy(butch). 
playsAirGuitar(butch):- 
    listens2Music(butch).

這是一種用來聲明“Butch會彈空氣吉他,如果他在聽歌,或者他很快樂。”的方法。列出相同頭部的規則是一種表示邏輯或的方法(就是一種表示或者的方法)。所以,如果我們查詢:

?-  playsAirGuitar(butch).

prolog會回答yes。第一條規則不起作用(因爲KB3無法得出happy(butch) ),但是KB3中包含 listens2Music(butch) ,所以prolog會用這條規則來進行演繹推論:

playsAirGuitar(butch):- 
    listens2Music(butch).

以此推導出playsAirGuitar(butch) 。

還有一種方法來表示,就是把兩個規則合併爲一個:

playsAirGuitar(butch):- 
    happy(butch); 
    listens2Music(butch).

其實用分號就可以,這是prolog用來表示或的符號。所以這一條規則其實就等於上面兩條規則。

分開寫和用分號,哪個更好?視情況而定。一方面,許多的分號會使得代碼可讀性變差,另一方面,如果prolog只需要處理一條規則效率就會更高。

現在就很清楚了,prolog與邏輯有關。:- 表示如果","表示連接";"表示(那麼怎麼表示?這就是另一件事了。我們會在第十章討論。)此外,我們已經開始瞭解,”Prolog“是”Programming with logic” 縮寫的原因了。

知識庫4

KB4:

woman(mia). 
woman(jody). 
woman(yolanda). 

loves(vincent,mia). 
loves(marsellus,mia). 
loves(pumpkin,honey_bunny). 
loves(honey_bunny,pumpkin).

這是一個很無聊的知識庫。沒有規則,只有事實。但這是我們第一次看到有兩個名字做參數的謂詞(謂詞loves)。

但這次最新奇的地方不在知識庫,而在與我們發出查詢的方式。這是我們第一次用變量,例子如下:

?-  woman(X).

這就是X變量(任何大寫字母開頭的字符串就可以作爲prolog的變量,這就是爲什麼我們前面一直小心的使用小寫字母)。變量不是名字,是一個佔位符。就相當於向prolog問:告訴我所有人中哪一個(X)是女人(woman)。

Prolog爲了回答這個問題,遍歷了KB4,試圖找到(或匹配到)與woman(X)匹配的信息。現在,知識庫的第一條就是woman(mia)。所以,Prolog把X與mia合一(unifies),完美的滿足了查詢。(這個過程有不同的術語,比如:把X實例化爲mia,或者把X綁定爲mia。)然後Prolog會返回:

X  =  mia ?

我們要讓他顯示更多匹配的項目,所以我們要在後面打一個";"。分號意味着“或”,所以我們打一個分號就相當於在說:還有什麼其他匹配的嗎?所以Prolog會再次查詢知識庫(從上次結束的地方)。然後發現X與jody合一。遂返回:

X  =  jody ?

以此類推:

X  =  yolanda ?

yes

因爲匹配結束,所以返回了 yes。


知識庫裏還有四條與love有關的條目,他們無法與woman(X)合一。讓我們來嘗試一種更復雜的查詢:

?-  loves(marsellus,X),  woman(X).

","意味着“與”,所以這句查詢的就是說:誰是X,Marsellus喜歡X並且X是女人?顯而易見:Mia是女人(事實1)並且Marsellus喜歡mia(事實5)。Prolog會找出這個解,在遍歷知識庫後會把X與mia合一,使其同時滿足兩個查詢(以後我們會學習Prolog是如何做的)。所以Prolog返回:

X = mia

yes

把變量與知識庫裏的信息是Prolog的核心。正如我們知道的,prolog有很多有趣的概念。但隨着我們深入,我們會發現,返回變量綁定(合一)的值是最關鍵的。

知識庫5

我們已經介紹了變量,但我們到現在也只在查詢裏用過。變量可以在知識庫裏使用,而且也僅有這樣使用,我們我們才能寫出真正有趣的程序。來看看KB5:

loves(vincent,mia). 
loves(marsellus,mia). 
loves(pumpkin,honey_bunny). 
loves(honey_bunny,pumpkin). 

jealous(X,Y):-  loves(X,Z),  loves(Y,Z).

KB5有四個loves事實和一條規則。(事實和規則之間的空行沒有任何意義,只是爲了增加可讀性。如前所述,prolog在排版上給了很大自由。)但這條規則是迄今爲止最有趣的一條:它包含了三個變量(X,Y,Z)。那它是什麼意思呢?

事實上,它定義了“嫉妒”。它說:X嫉妒Y,如果X loves Z,且Y loves Z。(好吧,現實並不是簡單。)但重要的是,它指明瞭一個規範,而不是針對誰。當它被聲明瞭,那麼它在整個程序裏都有效。如果我們發出如下查詢:

?-  jealous(marsellus,W).

查詢的意思是:Marsellus 嫉妒 的 W 是誰?顯而易見,Vincent和Marsellus都喜歡mia。所以prolog會返回:

W  =  vincent

給你留些題目:首先,KB5中還有那些嫉妒的關係?進一步,如果我們要prolog告訴我們所有嫉妒的關係,你要怎麼查詢?它給的結果有使你驚訝的嗎?有很蠢的地方嗎?(想想爲什麼。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章