Max Bramer:logic Programming With Prolog@2013 (第2版)
以下是從提供的資料中提取並詳盡解釋的主要論點:
Prolog 的核心哲學與基礎建構
Prolog 是一種與傳統程序式程式語言(如 C 或 Java)截然不同的程式語言,其核心在於邏輯編程範式。Prolog 的程式並非一系列按順序執行的指令,而是對已知事實和規則的聲明式描述。這種聲明式方法(Declarative Programming)關注於「是什麼」(What is true),而不是「如何做」(How to compute),與描述計算步驟的程序式方法形成鮮明對比。Prolog 的設計深受數學邏輯和自動定理證明研究的影響,其程式可以被視為一個邏輯理論,而查詢則是需要證明的定理。
Prolog 程式的基本建構單元只有三種:事實 (Facts)、規則 (Rules)和查詢 (Queries)。
* 事實用於聲明無條件為真的知識,例如 dog(fido). 表示「fido 是狗」。
* 規則用於聲明有條件為真的知識,形式為 頭部 :- 體部.,表示「頭部為真,如果體部為真」。體部包含一個或多個由逗號分隔的目標(Goals),逗號表示邏輯「且」。例如 animal(X) :- dog(X). 表示「對於任何 X,如果 X 是狗,那麼 X 是動物」。
* 查詢是用戶向 Prolog 系統提出的問題,系統嘗試根據事實和規則來證明查詢是否為真。查詢可以包含變量,系統會嘗試找到使查詢為真的變量綁定。
事實和規則統稱為子句 (Clauses),它們共同構成了程式的謂詞 (Predicates)定義。一個謂詞由所有具有相同函子(名稱)和元數(參數個數)的子句組成。Prolog 程式實際上就是一個由子句構成的數據庫。
數據表示:項 (Terms)
在 Prolog 中,所有的數據對象都被稱為項 (Terms)。項是 Prolog 處理的基本單位,可以分為幾種類型:
* 數字 (Numbers):整數(如 100, -5)和(通常)浮點數(如 3.14)。
* 原子 (Atoms):常量,類似於其他語言中的字符串或符號,但有特定的命名規則。以小寫字母開頭的字母、數字、下劃線序列(如 john, my_atom)或用單引號括起來的任意字符序列(如 'Hello World', 'a-b')。
* 變量 (Variables):以大寫字母或下劃線開頭的字母、數字、下劃線序列(如 X, Person, _123)。變量用於表示未知或可變的值。特殊的匿名變量 (Anonymous Variable) _ 用於表示不關心其值的變量。
* 複合項 (Compound Terms):由一個函子(原子)和一組參數(項)組成,寫作 函子(參數1, 參數2, ...),例如 likes(john, mary)。函子的參數個數稱為其元數 (Arity)。複合項是 Prolog 中表示結構化數據的核心方式,類似於記錄或結構體。
* 列表 (Lists):一種特殊的複合項,用於表示任意數量的項的有序序列,寫作 [元素1, 元素2, ...],例如 [dog, cat, 123, mypred(a), [a, b]]。列表非常靈活,可以包含任何類型的項,包括其他列表。空列表表示為 []。列表通常用 Cons 表示法 [頭部|尾部] 來處理,頭部是列表的第一個元素,尾部是其餘元素的列表,這對於遞歸處理列表非常有用。
原子和複合項統稱為可呼叫項 (Call Terms),因為它們可以用作查詢或規則體中的目標。
程式執行機制:統一 (Unification) 與回溯 (Backtracking)
Prolog 執行查詢的核心機制是統一 (Unification)和回溯 (Backtracking),這構成了其內建的定理證明過程。
* 統一:當系統嘗試滿足一個目標時,它會搜尋數據庫中具有相同謂詞(相同函子和元數)的子句。如果目標與子句的頭部「統一」,則表示匹配成功。統一是一個使兩個項變得相同的過程,通常涉及將變量綁定 (Binding)到特定的值。例如,目標 dog(X) 與事實 dog(fido) 可以統一,通過將變量 X 綁定到原子 fido。
* 回溯:如果一個目標有多種統一的可能性(例如,有多個事實或規則的頭部與目標統一),或者當一個目標的體部包含多個子目標,而其中一個子目標失敗時,Prolog 系統會自動觸發回溯。回溯是指系統返回到最近一個成功滿足的目標,嘗試尋找另一種滿足它的方式(即與下一個可統一的子句進行統一)。這個過程會系統地探索所有可能的解。
Prolog 預設的目標評估順序是從左到右處理規則體中的子目標,而子句的匹配則是從上到下按照它們在數據庫中的順序進行。這種固定的順序對於實際程式的執行行為至關重要,尤其是在涉及輸入/輸出或動態數據庫修改時。
控制流程:遞歸與回溯控制
雖然缺乏傳統的循環結構(如 for, while 循環),Prolog 提供了強大的機制來實現重複和條件執行:
* 遞歸 (Recursion):這是 Prolog 中實現重複計算和處理數據結構(尤其是列表)的基本和最常見的方法。一個謂詞可以通過調用自身來定義,需要包含一個或多個終止條件(Base Cases)來停止遞歸。
* repeat 謂詞:一個特殊的內建謂詞,總是在被調用時成功,並且在回溯時也能無限次成功。它可以與 fail 或其他測試條件結合使用,構造出基於回溯的循環。
* Backtracking with Failure:通過在規則體中使用 fail 謂詞,可以強制回溯,配合目標評估順序,可以實現遍歷整個數據庫以尋找所有匹配項的效果。
* Cut (剪斷/剪枝):特殊的內建謂詞 ! 用於限制回溯。一旦 ! 被執行,Prolog 就不能再回溯到 ! 之前的目標去尋找其他的解,也不能嘗試與當前規則頭部以外的子句進行統一。Cut 是一個強大的工具,但也可能導致程式的非聲明性行為和潛在的錯誤,需謹慎使用。!, fail 的組合常用於定義例外情況或強制失敗。
輸入輸出與數據庫操作
Prolog 提供了處理輸入和輸出的內建謂詞:
* 項的輸入輸出:read(X) 從當前輸入流讀取一個項(需以句號結束),並嘗試與 X 統一。write(Term) 和 writeq(Term) 向當前輸出流寫入一個項。
* 字符的輸入輸出:get0(X) 和 get(X) 從當前輸入流讀取一個字符的 ASCII 值。put(N) 向當前輸出流寫入一個 ASCII 值對應的字符。
* 文件操作:see(Filename) 將當前輸入流切換到指定文件。tell(Filename) 將當前輸出流切換到指定文件。seen 和 told 分別關閉當前輸入/輸出文件並將流切換回用戶終端 (user)。
Prolog 程式本身就是數據庫,其內容可以在程式執行時被修改。
* 動態謂詞 (Dynamic Predicates):預設情況下,從文件載入的謂詞是靜態的,不能在執行時修改。需要通過 :- dynamic(謂詞/元數). 指示來聲明謂詞為動態的,才能進行修改。
* 修改數據庫:assertz(Clause) 在謂詞子句列表末尾添加一個子句。asserta(Clause) 在謂詞子句列表開頭添加一個子句。retract(Clause) 刪除第一個與 Clause 統一的子句。retractall(Head) 刪除所有頭部與 Head 統一的子句。這些功能使得構建動態知識庫或外殼程序成為可能。
高級特性與應用
Prolog 包含一些高級特性,增強了其表達能力和靈活性:
* 運算符定義:用戶可以定義自己的運算符(通過 op/3 謂詞),包括前綴、中綴和後綴運算符,並指定它們的優先級,從而創建更具可讀性的程式碼(例如,自定義數學運算、字符串連接或集合操作符)。
* 項處理謂詞:Prolog 可以將項分解為其組成部分,或從組成部分構造項。
* Term =.. List (univ 運算符) 在項和表示該項結構的列表之間進行轉換(列表的第一個元素是函子,其餘是參數)。
* functor(Term, Functor, Arity) 獲取或構造項的函子和元數。
* arg(N, Term, Arg) 獲取複合項的第 N 個參數。
* call(Goal) 將一個項作為目標來執行。這些謂詞對於編寫元程式(處理其他 Prolog 程式的程式)和需要靈活處理結構化數據的應用非常有用。
* 字符串處理:雖然原子是基本的字符串形式,Prolog 通常通過 name(Atom, ListOfCharCodes) 謂詞將原子轉換為字符代碼列表,然後利用列表處理技術進行操作。
* 語法規則 (Grammar Rules):Prolog 提供特殊的 --> 符號來方便地定義和處理上下文無關文法(如分析自然語言句子)。語法規則本質上是 Prolog 子句的語法糖,簡化了文法定義。phrase(SyntacticTerm, ListOfWords) 謂詞用於測試列表是否符合文法規則。
這些特性使 Prolog 特別適合處理符號性、邏輯性強的問題,如人工智能領域的應用,包括自然語言理解、專家系統、自動規劃和約束滿足問題。Prolog 的聲明式特性和內建的回溯機制,使其在許多情況下能以比程序式語言更簡潔、更優雅的方式解決複雜問題。
comments
comments for this post are closed