Prolog/引言
本節介紹如何安裝 Prolog 編譯器、載入第一個程式並對其進行查詢。然後解釋如何在程式和查詢中使用事實和變數。
在開始任何操作之前,需要在您的系統上安裝 Prolog 編譯器和文字編輯器。文字編輯器允許您編寫 Prolog 程式,而 Prolog 編譯器(也稱為直譯器)則允許您執行它們。
Prolog 編譯器
以下 Prolog 實現是免費的(至少用於個人或教育用途,請務必閱讀條款)。只需下載一個並根據網站上的說明進行安裝。
- B-Prolog
- http://www.picat-lang.org/bprolog/
- 一個標準 Prolog 編譯器,具有諸如表格和約束求解等擴充套件功能。支援多種平臺。
- SWI Prolog(推薦用於本書)
- https://www.swi-prolog.org/
- 一個小型且健壯的開源實現,符合 Prolog 標準(ISO 和 Edinburgh),並具有許多額外的庫和內建謂詞。甚至還有一個用於建立視窗和圖形的單獨工具包,稱為 XPCE。支援多種平臺。
- GNU Prolog
- http://www.gprolog.org/(曾為:http://pauillac.inria.fr/~diaz/gnu-prolog/)
- 一個相對較新的開源實現。支援約束邏輯程式設計,這是 Prolog 的一種擴充套件。
- Visual Prolog
- http://www.visual-prolog.com/
- 一個完整的 Prolog 面向物件擴充套件開發環境。包括編譯器、連結器、文字編輯器、圖形對話方塊編輯器、構建系統、偵錯程式、大型庫等等。
以下實現不是免費的
- SICSTUS Prolog
- http://www.sics.se/
- 可能是最著名的專業 Prolog 實現和開發套件。符合 ISO 標準,許多庫和對約束邏輯程式設計的支援。免費評估。
- Quintus Prolog
- http://www.sics.se/quintus/
- 一個特別健壯可靠的實現,旨在用於商業用途和研究專案,由與 SICSTUS 同一家公司開發。免費評估。
文字編輯器
您將編寫的程式是簡單的文字檔案,可以使用任何文字編輯器進行讀取和寫入。一些 Prolog 實現帶有自己的編輯器,但對於那些沒有的實現,這裡列出了一些文字編輯器。這些提供了編寫 Prolog 程式所需的基本功能,例如縮排、括號匹配,有些甚至可以調整以突出顯示 Prolog 程式碼的語法。
- Crimson Editor
- http://www.crimsoneditor.com/
- 一個免費的 Windows 文字編輯器,具有許多功能。
- GNU Emacs
- http://www.gnu.org/software/emacs/emacs.html
- Unix 經典文字編輯器的免費開源實現。可能難以理解,但功能豐富。
- Vim
- http://www.vim.org/
- Emacs 長期競爭對手的免費開源實現。
- Textpad
- http://www.textpad.com/
- 一個具有許多功能的 Windows 文字編輯器。免費評估。
- Eclipse Prolog 外掛
- http://eclipse.ime.usp.br/projetos/grad/plugin-prolog/index.html
- 一個免費的 Eclipse 外掛。
安裝完 Prolog 實現後,就可以編寫第一個程式並將其載入到直譯器中(主要是為了檢查一切是否正常)。啟動您的文字編輯器,並建立一個文字檔案,其中只包含以下一行
human(john).
請務必準確,Prolog 中大小寫敏感,句點也很重要。這將是您的程式(也稱為**資料庫**或**知識庫**)。為其指定一個好聽的名字,例如 prolog1.pl 並儲存。注意:副檔名 pl 未正式與 Prolog 關聯,如果也使用 Perl 程式設計,它也使用 .pl,可能會導致衝突。如果出現此問題,您可以使用 pro 或 pr 或任何您喜歡的名稱。現在啟動您的 Prolog 直譯器。大多數 Prolog 直譯器會顯示一個包含一些啟動資訊的視窗,然後顯示一行
?-
並在其後顯示一個游標。通常有一個選單用於將檔案載入到直譯器中。如果沒有,您可以鍵入以下內容載入您的檔案
consult('FILEPATH').
然後按 Enter。再次強調,請務必準確,不要使用大寫字母,並記住句點。將 FILEPATH 替換為您檔案的名稱和目錄。例如,如果您的檔案位於 C:\My Documents\Prolog\prolog1.pl,則使用
consult('c:/my documents/prolog/prolog1.pl').
或簡寫
['c:/my documents/prolog/prolog1.pl'].
請注意,斜槓的方向相反,因為反斜槓 (\) 在 Prolog(和大多數其他語言)中具有特殊含義。如果您使用的是基於 UNIX 的系統(例如 Linux),則命令可能如下所示
consult('/home/yourName/prolog/prolog1.pl').
['/home/yourName/prolog/prolog1.pl'].
您的直譯器現在應該會告訴您檔案已成功載入。如果未成功載入,請查閱您的實現的幫助檔案或手冊以瞭解如何載入檔案。
此外,您可以告訴 Prolog 直譯器在使用 -s 鍵執行時自動載入檔案,如下所示[1]
prolog -s /home/yourName/prolog/prolog1.pl
顯示一些資訊後,您將看到
?-
要檢視一切是否正常,請鍵入
human(john).
(不要忘記句點)然後按 Enter。Prolog 將回答
true.
鍵入
human(Who).
,按 Enter,Prolog 將回答
Who = john.
要退出 Prolog,請鍵入
halt.
上一示例中的 human(john). 行是一個謂詞形式的 Prolog 語句。此類語句稱為事實。謂詞由一個或多個字元組成的一個單片語成,全部小寫,後面可能跟著若干個項。以下是有效謂詞的示例
human(john) father(david, john) abc(def,ghi,jkl,m) tree p(a ,f ,d)
項(括號內的“單詞”)可以採用多種形式,但現在我們將堅持使用常量。這些是單詞,同樣全部小寫。謂詞和常量的第一個字元都需要是字母。使用謂詞,我們可以向程式新增事實
human(john). human(suzie). human(eliza). man(david). man(john). woman(suzie). woman(eliza). parent(david, john). parent(john, eliza). parent(suzie, eliza).
請注意每行後面的句點“.”,表示該行結束。這一點非常重要,如果忘記了,您的直譯器將無法理解程式。您還應該注意,為謂詞和項選擇的名稱實際上對 Prolog 直譯器沒有任何意義。它們只是為了顯示程式的含義。我們可以輕鬆地將 human 替換為 spaceship,直譯器將無法分辨。
如果我們將上述程式載入到直譯器中,我們就可以對其執行一個查詢。如果您鍵入
human(john).
Prolog 將回答
true.
如果您鍵入
woman(john).
Prolog 將回答
false.
這看起來也很明顯,但重要的是要以正確的方式理解它。如果您向 Prolog 提問 human(john).,則表示您正在詢問 Prolog 此語句是否為真。顯然,Prolog 無法從語句中看出它是否為真,因此它會查閱您的檔案。它會檢查程式中的所有行,以檢視是否有任何行與該語句匹配,如果找到匹配項,則回答 Yes。如果沒有找到匹配項,則回答 false.。請注意,如果您詢問
?- human(david).
Prolog 將回答 false.,因為我們尚未將該事實新增到資料庫中。這一點很重要:如果 Prolog 無法從程式中證明某件事,它將認為它不正確。這被稱為封閉世界假設。
我們將使用 human(david) 更新程式,以便資料庫中的所有人都是人類,並且是男性或女性
human(david). human(john). human(suzie). human(eliza). man(david). man(john). woman(suzie). woman(eliza). parent(david, john). parent(john, eliza). parent(suzie, eliza).
我們現在擁有的仍然不是一種表達能力很強的語言。透過在查詢中使用變數,我們可以獲得更大的表達能力。變數是一個單詞,就像項和謂詞一樣,但它以大寫字母開頭,之後可以包含大小寫字元。考慮以下查詢
human(A).
現在,謂詞的項是一個變數。Prolog 將嘗試將項繫結到變數。換句話說,您正在詢問 Prolog,A 需要是什麼才能使 human(A) 為真。
?- human(A).
Prolog 將回答
A = david ;
這是真的,因為資料庫包含行 human(david)。如果您按 Enter,Prolog 將回答 Yes 並將游標返回給您。如果您按分號 ;,Prolog 將顯示其餘的可能性
A = john ; A = suzie ; A = eliza.
在eliza之後,沒有其他的可能性了。如果你用多個變數查詢Prolog,它會顯示所有使查詢為真的變數例項化。
?- parent(Parent, Child). Parent = david Child = john ; Parent = john Child = eliza ; Parent = suzie Child = eliza ; No
當Prolog被要求用一個變數進行查詢時,它會檢查程式的所有行,並嘗試將每個謂詞統一到查詢中。這意味著它會檢查當變數以某種方式例項化時,查詢是否與謂詞匹配。它可以透過使A為john來將human(A)與human(john)統一,但它不能將man(A)與human(john)統一,因為謂詞不匹配。
如果我們想讓Prolog更難處理,我們可以在查詢中使用兩個謂詞,例如
?- human(A), parent(B,A).
現在我們要求Prolog找出一個名叫A的人,其父母為B。逗號表示並且,表示兩個謂詞都需要為真,查詢才能為真。為了檢查這個查詢,Prolog首先會找到一個例項化來使第一個謂詞為真——假設它使A等於john——然後它會嘗試使第二個謂詞為真——A等於john。如果它找到了兩個使這兩個謂詞都為真的A和B的例項化,它會將它們返回給你。你可以按Enter鍵結束程式,或按分號檢視更多選項。
Prolog可能會為A選擇一個滿足第一個謂詞但與第二個謂詞不匹配的選項。假設它選擇A = suzie來滿足human(A);沒有B的選擇可以滿足parent(B, suzie),所以Prolog會放棄對A的選擇suzie,並嘗試另一個名字。這稱為回溯。
在上面的例子中,Prolog首先會在程式中找到human(david)並將A與david統一。為了使第二個謂詞為真,它需要找到parent(B, david)的例項化。它找不到任何例項化,所以它會尋找human(A)的新例項化。它嘗試下一個選項:A = john。現在它需要例項化parent(B, john)。它在行parent(david, john)中找到B = david,並將其報告給你。
A = john B = david
如果你按下分號,它會嘗試找到第二個謂詞的新例項化。如果失敗,它會嘗試找到第一個謂詞的新例項化,依此類推,直到它用完所有選項。
有一個特殊的變數,稱為匿名變數,使用下劃線(_)字元。當你在查詢中使用這個字元時,你基本上是在說你不在乎這個變數是如何例項化的,也就是說,你不在乎它繫結到哪個項,只要它繫結到某個東西即可。如果你詢問Prolog
?- parent(A, _).
Prolog 將回答
A = david; A = john; A = suzie;
它不會告訴你它是如何例項化_的。但是,如果你詢問Prolog
?- abc(_,_,_).
預設情況下,這將不會為真,Prolog需要在資料庫中找到所有三個匿名變數的例項化,例如abc(d,e,f)。由於謂詞abc根本不在資料庫中,因此查詢失敗。你也可以在你的資料庫中使用匿名變數。放置
human(_).
在你的資料庫中意味著任何項,無論它是否已經存在,都是human。因此,查詢
?- human(mark).
和
?- human(orange).
在資料庫中存在上述事實的情況下將為真。這裡匿名變數用於宣告所有物件的屬性,而不僅僅是一個物件。如果我們想宣告特定的一組物件具有某個屬性,我們需要規則。下一節將對此進行處理。
以下程式描述了一些城市的公共交通系統
transport(dresden, tram). transport(amsterdam, tram). transport(amsterdam, subway). transport(new_york, subway).
我們可以詢問Prolog是否存在一個城市同時擁有有軌電車系統和地鐵系統
?- transport(A, subway), transport(A, tram). A = amsterdam ; fail.
(x)在某個地方找到一個家譜,或自己編造一個(真實的更容易檢查你的答案)。使用謂詞woman/1、man/1、parent/2在Prolog程式中實現部分家譜(大約十個人)。謂詞後面的數字描述了謂詞接受多少個引數。因此,parent/2描述了一個像parent(john, mary)這樣的謂詞。
你可以瀏覽w:Category:Family_trees以獲取合適的家譜。
為以下命令和問題編寫Prolog查詢。如果某些人被多次返回,請不要擔心。我們稍後將瞭解如何處理這種情況。
- 列出資料庫中的女性。
- 列出資料庫中的兒童。
- 列出所有父子組合。
- 哪些女性在資料庫中既有父親又有兒子?
你能想到一種方法來顯示資料庫中沒有列出父親的女性嗎?你能描述一下編寫此類查詢需要什麼嗎?
某些練習的答案可以在此處找到:Prolog/Introduction/Answers
- ↑ 使用SWI-Prolog時,不確定其他版本是否相同。
下一章:規則