Learn Prolog Now 翻譯 - 第九章 - 語句深究 - 第三節, 語句的檢查

內容提要

  • 語句的類型檢查
  • 語句的結構檢查
  • 字符串

在本節中,咱們將學習一些內置謂詞,這些謂詞能夠對語句進行檢查。首先,咱們將會看到的謂詞會測試其參數的語句是否爲某種特定的類型(好比,是不是原子或者數字)。接下來,會介紹一些能夠揭示覆雜語句結構的謂詞。app


語句的類型檢查

回憶一下在第一章咱們學習關於Prolog語句的內容:一共有四種類型的語句,分別爲:變量,原子,數字和複雜語句。更進一步來講,原子和數字能夠歸類爲常量,常量和變量歸類爲簡單語句。下面的樹狀圖總結的這些內容:學習


有時可以知道給出的語句的類型是什麼是很用的。好比,你也許想要寫一個謂詞,其中不得不對不一樣類型的語句,選擇不一樣的處理方式。Prolog提供了幾個內置的謂詞,可以檢查語句是不是特定的類型:測試

atom/1:檢查參數語句類型是否爲原子?編碼

integer/1:檢查參數語句類型是否爲整數?atom

float/1:檢查參數語句類型是否爲浮點數?code

number/1:檢查參數語句類型是否爲數字?blog

atomic/1: 檢查參數語句類型是否爲常量?字符串

var/1:檢查參數語句類型是否爲未初始化的變量?io

nonvar/1:檢查參數語句類型是否爲已經被初始化的變量或者其餘非未初始化變量的類型?字符編碼



讓咱們觀察一下這些謂詞的行爲:

?- atom(a).
true

?- atom(7).
false

?- atom(loves(vincent, mia)).
false

這裏的三個例子的結果正如咱們的指望。可是,若是咱們將變量做爲參數傳入atom/1,會發生什麼?

?- atom(X).
false

這很好理解,由於一個爲初始化的變量不是一個原子。可是若是咱們將X初始化爲一個原則,而後再查詢atom(X),Prolog會回答true:

?- X = a, atom(X).
X = a
true

可是這裏重要的一點是初始化必須在檢查以前完成:

?- atom(X), X = a.
false

謂詞integer/1和float/1的做用相似,能夠本身嘗試一些例子。



下面來學習number/1和atomic/1兩個謂詞。首先,number/1會檢查語句是否爲整數或者浮點數,即,number/1爲真若是integer/1爲真或者float/1爲真,number/1爲假若是integer/1和float/1都爲假。其次是atomic/1,會檢查語句是否爲常量,即語句是否爲原子或者數字。因此,atomic/1爲真若是atom/1或者number/1爲真,atomic/1爲假若是atom/1和number/1都爲假。

?- atomic(mia).
true

?- atomic(8).
true

?- atomic(3.25).
true

?- atomic(loves(vincent, mia)).
false

?- atomic(X)
false



那麼變量如何檢查呢?首先有var/1這個謂詞,能夠檢查語句是否爲未初始化的變量:

?- var(X).
true

?- var(mia).
false

?- var(8).
false

?- var(3.25)
false

?- var(loves(vincent, mia)).
false

其次還有nonvar/1謂詞,當var/1爲假時,這個謂詞結果爲真,即它能夠檢查語句不是未被初始化的變量:

?- nonvar(X).
false

?- nonvar(mia).
true

?- nonvar(8).
true

?- nonvar(3.25).
true

?- nonvar(loves(vincent,mia)).
true

請注意一個包含了未初始化變量的複雜語句自己不是一個未初始化的變量(它仍是一個複雜語句),因此:

?- var(loves(_, mia)).
false

?- nonvar(loves(_, mia)).
true

當X被初始化,var(X)和nonvar(X)的結果依賴於它們是在X初始化前被調用,仍是後被調用,以下:

?- X = a, var(X).
false

?- X = a, nonvar(X).
X = a
true

?- var(X), X = a.
X = a
true

?- nonvar(X), X = a.
false


語句的結構檢查

假設有一個未知結構的複雜語句(好比一些謂詞將複雜語句做爲輸出參數),咱們但願從中獲取哪些信息?明顯的回答是:它的函子,元數,及其參數看上去是什麼樣的。Prolog提供了內置的謂詞能夠獲取這些信息。謂詞functor/3能夠獲取複雜語句的函子和元數信息。好比:

?- functor(f(a, b), F, A).
A = 2
F = f
true

?- functor([a, b, c], X, Y).
X = '.'
Y = 2
true

注意到查詢列表時,Prolog返回的函子是.,這是列表在Prolog內部的表示法。

當對常量使用functor/3時,會發生什麼?讓咱們試試:

?- functor(mia, F, A).
A = 0
F = mia
true

?- functor(8, F, A).
A = 0
F = 8
true

?- functor(3.25, F, A).
A = 0
F = 3.25
true

因此咱們可使用謂詞functor/3找出任何語句的函子和元數,包括一些元數爲0的語句(好比常量)。



咱們也可以使用functor/3構建語句。如何作?經過將第二個和第三個參數傳入具體的值,而第一個參數是未初始化的變量,好比:

?- functor(T, f, 7).
T = f(_G286, _G287, _G288, _G289, _G290, _G291, _G292)
true

請注意第一個,或者第二個和第三個參數必須被初始化。好比,若是查詢 functor(T, f, N),Prolog就會報錯。若是你想查詢的問題有意義,Prolog會用合理的方式回答。可是要求Prolog構建一個複雜語句可是不告訴它須要幾個參數,這就不是有意義的要求了,Prolog就處理不了。

如今咱們已經學習了functor/3,讓咱們實際使用它完成一些工做。在本節前面的內容中,咱們討論了一些內置的檢查語句類型的謂詞,包括檢查語句是否爲:原子,數字,常量,或者變量。可是沒有謂詞能夠檢查語句是否爲複雜語句。爲了使得檢查類型謂詞列表完整,咱們本身定義一個謂詞。使用functor/3能夠很容易完成,咱們要作的就是檢查參數是不是一個合理的函子,並且有輸入參數(即,它的元數大於0),下面是定義:

?- complexterm(X) :-
    nonvar(X),
    functor(X, _, A),
    A > 0.


函子到此爲止,那麼參數呢?做爲functor/3的補充,Prolog爲咱們提供了謂詞arg/3,能夠獲取複雜語句中的參數。它獲取數字N和複雜語句T,返回複雜語句第N個參數,可使用這個謂詞訪問一個參數的值:

?- arg(2, loves(vincent, mia), X).
X = mia
true

或者初始化參數:

?- arg(2, loves(vincent, X), mia).
X = mia
true

試圖訪問一個不存在的參數,會失敗:

?- arg(2, happy(yolanda), X)
false



謂詞functor/3和arg/3容許咱們訪問全部咱們但願知道的關於複雜語句的信息,同時,Prolog還提供了第三個內置謂詞:=../2(等號後面加上兩個句號),它會獲取一個複雜語句,而且返回一個列表,其中複雜語句的函子做爲列表頭元素,複雜語句的全部參數,構成列表的尾部,因此,若是咱們查詢:

?- =..(loves(vincent, mia), X).
X = [loves, vincent, mia]

這個謂詞(也稱爲univ)可以被看成中綴操做符使用,以下:

?- cause(vincent, dead(zed)) =.. X.
X = [cause, vincent, dead(zed)]
true

?- X =.. [a, b(c), d].
X = a(b(c), d)
true

?- footmassage(Y, mia) =.. X.
Y = _G303
X = [footmassage, _G303, mia]
true

當某些狀況下,須要訪問一個複雜語句全部的參數時,univ會派上用場,因爲返回的是一個列表,因此全部列表操做的方法和策略均可以使用。


字符串

Prolog中經過字符(ASCII)編碼的列表來表示字符串。可是,因爲使用列表語法去操做字符串很彆扭,因此Prolog提供了更加友好的字符串語法:使用雙引號,嘗試一下查詢:

?- S = "Vicky".
S = [86, 105, 99, 107, 121]
true

這裏將變量S和字符串「Vicky」合一,其實是有5個數字的列表,每個數字表明一個字符編碼。(好比,86是字符V的編碼,105是字符i的編碼,等等)

換句話講,Prolog中的字符串其實是數字的列表。絕大多數的Prolog方言都提供了標準的一些謂詞來處理字符串。一個特別有用的謂詞是atom_codes/2,它會把一個原子轉換爲一個字符串。下面的例子展現了atom_codes/2可以作些什麼:

?- atom_codes(vicky, X).
X = [118, 105, 99, 107, 121]
true

?- atom_codes('Vicky', X).
X = [86, 105, 99, 107, 121]
true

?- atom_codes('Vicky Pollard', X).
X = [86, 105, 99, 107, 121, 32, 80, 111, 108 | ...]
true

還有另一種使用,atom_codes/2的方式,經過字符串生成原子。假設你想要將一個原子abc變成另外一個原子abcabc,那麼你能夠這麼作:

?- atom_codes(abc, X), append(X, X, L), atom_codes(N, L).
X = [97, 98, 99]
L = [97, 98, 99, 97, 98, 99]
N = abcabc

最後一件須要知道的事情是,和atom_codes/2相關的另一個內置謂詞,是number_codes/2,這個謂詞行爲方式很前者很相似,可是正如名字所示,只能做用於數字。

相關文章
相關標籤/搜索