Prolog中有四個知識庫相關的操做命令:assert,retract,asserta,assertz。讓咱們學習它們是如何使用的。假設從一個空白的知識庫開始,若是輸入命令:緩存
?- listing.
Prolog會簡單地回覆true,列表是空白的。app
假設咱們輸入這個命令:性能
?- assert(happy(mia)).
Prolog會回覆true(assert/1命令始終會成功)。可是重點不是這個命令可以成功,而是它對知識庫帶來的反作用。若是如今咱們輸入:學習
?- listing. happy(mia).
即,知識庫已經再也不是空白的了:它如今包含了咱們聲明的一個事實。code
假設咱們繼續輸入四個assert命令:內存
?- assert(happy(vincent)). true ?- assert(happy(marcellus)). true ?- assert(happy(butch)). true ?- assert(happy(vincent)). true
若是咱們如今查詢知識庫的內容:數學
?- listing. happy(mia). happy(vincent). happy(marcellus). happy(butch). happy(vincent). true
咱們聲明的全部事實如今都存在在知識庫中了。注意happy(vincent)在知識庫中存在兩個,由於咱們聲明瞭兩次,看上去是合理的。變量
咱們使用的知識庫操做實際上已經更新了謂詞happy/1的含義。更通用地講,知識庫操做命令給予了咱們在運行程序時更新謂詞的能力。在運行期間更新謂詞定義稱爲動態謂詞,與之相對的是咱們以前定義和使用的靜態謂詞。大多數Prolog解釋器都堅持認爲應該顯式地聲明動態謂詞。咱們將會稍後介紹包含動態謂詞的例子,如今讓咱們繼續討論知識庫操做命令。搜索
到此爲止,咱們只經過聲明往知識庫中添加了事實,可是咱們也能夠添加規則。假如咱們想要聲明一個規則說若是任何人很高興,那麼他就很天真,即:語法
naive(X) :- happy(X).
咱們能夠這麼作:
assert((naive(X) :- happy(X))).
請注意這個命令的語法:咱們聲明的規則使用一對小括號括起來。若是咱們如今問知識庫有哪些內容:
happy(mia). happy(vincent). happy(marcellus). happy(butch). happy(vincent). naive(A) :- happy(A).
如今咱們已經瞭解若是聲明新的信息到知識庫中,咱們應該也瞭解若是在不須要這些信息的時候,將它們從知識庫中移除。存在一個和assert/1相反的謂詞,名爲retract/1來達到這個目的。好比,若是咱們使用下面的命令:
?- retract(happy(marcellus)).
而後列出如今知識庫中的全部內容:
happy(mia). happy(vincent). happy(butch). happy(vincent). naive(A) :- happy(A).
能夠看到,happy(marcellus)這個事實已經被移除。
若是咱們繼續:
?- retract(happy(vincent)).
而後列出如今知識庫中的全部內容:
happy(mia). happy(butch). happy(vincent). naive(A) :- happy(A).
請注意第一個happy(vincent),並且只有第一個這樣的事實被移除。
若是想要移除咱們定義的happy/1全部的相關信息,能夠使用變量:
?- retract(happy(X)). X = mia; X = butch; X = vincent; false
如今的知識庫中,只剩下一個規則:
?- listing. naive(A) :- happy(A).
若是咱們但願對聲明的位置有更多的控制,這裏有兩個assert/1的變種,分別是:
好比,假設咱們從一個空白知識庫開始,而後給出以下的命令:
?- assert( p(b)), assertz(p(c)), asserta(p(a)).
而後列出知識庫中全部的內容:
?- listing. p(a). p(b). p(c). true
知識庫操做是一項有用的技術。特別是用於保存計算結果時,因此在之後再問相同的問題,咱們就能夠不用再從新計算一次:咱們只須要在聲明的事實中直接查詢保存的結果便可。這種技術稱爲內存化,或者緩存,這種技術在一些應用中能夠顯著地提高性能。下面是如何使用這項技術的簡單示例:
:- dynamic lookup/3. add_and_square(X, Y, Res) :- lookup(X, Y, Res), !. add_and_square(X, Y, Res) :- Res is (X + Y) * (X + Y), assert(lookup(X, Y, Res)).
這個程序作了什麼?基本上講,它使用兩個數字X和Y,將它們相加,而後進行平方運算得出結果。好比,咱們查詢:
?- add_and_square(3, 7, X). X = 100 true
可是重點在於:程序如何實現?首先,須要注意的是咱們已經聲明lookup/3爲一個動態謂詞。咱們須要在運行時可以修改lookup的定義。其次,請注意定義add_and_square/3時存在兩個子句。其中第二個子句是數學運算,而且將結果使用lookup/3謂詞保存到知識庫中(即,緩存了運算結果)。第一個子句檢查Prolog的當前知識庫,看是否存在已經運算過的結果,若是存在,就簡單地返回結果,並中斷第二個子句的執行。
下面是程序運行的例子。假設咱們進行另外一個查詢:
?- add_and_square(3, 4, Y). Y = 49 true
若是咱們如今查詢知識庫中存在的信息會發現已經包括了:
lookup(3, 7 ,100). lookup(3, 4, 49).
若是咱們再問Prolog關於3,4相加後平方的查詢,將不會再進行計算,而是直接返回已經計算過的結果。
有一個問題:咱們如何刪除全部咱們再也不須要的事實,若是咱們輸入命令:
?- retract(lookup(X, Y, Z)).
Prolog將會一個一個搜索全部的事實,而後詢問咱們是否想要刪除它們。可是存在一個更加簡便的方式,使用下面的命令:
?- retract(lookup(_, _, _)).
這個命令將會移除知識庫中全部lookup/3相關的事實。
關於知識庫操做的應用,還有一些建議:雖然這是一項有用的技術,可是知識庫操做可以致使一些不美觀,難以理解的代碼出現;若是你在一個存在不少回溯的程序中大量使用它們,理解程序含義會成爲噩夢。它是Prolog中一項沒有良好聲明性,非邏輯的技術,咱們須要很是當心地使用它。