1. 程式人生 > >Prolog教程 11-聯合(Unification)

Prolog教程 11-聯合(Unification)

匿名變數(_)不會繫結為任何值
如果使用(=)那麼聯合操作時顯式的。而Prolog在使用子句與目標匹配時的聯合則是隱式的。
Prolog的最強大的功能之一就是它內建了模式匹配的演算法----聯合(Unification)。以前我們所介紹的例子中的聯合都是較為簡單的。現在來仔細研究一下聯合。下表中列出了聯合操作的簡要情況。

變數&任何專案: 變數可以與任何專案繫結,其中也包括變數
原始專案&原始專案: 兩個原始專案(原子或整數)只有當它們相同時才能聯合。
結構&結構: 如果兩個結構的每個相應的引數能聯合,那麼這兩個結構可以聯合。

為了更清楚地介紹聯合操作,我們將使用Prolog的內部謂詞‘=/2’,此謂詞當它的兩個引數能夠聯合時成功,反之則失敗。它的語法如下:

=(arg1, arg2)

為了方便閱讀,也可以寫成如下形式:

arg1 = arg2

注意:此處的等號在Prolog中的意義與其他語言中的不同。它不是數學運算子或者賦值符。

使用=進行聯合操作與Prolog使用目標與子句聯合時相同。在回溯時,變數將被釋放。

下面舉了幾個最簡單的聯合的例子。

?- a = a.
yes

?- a = b.
no

?- location(apple, kitchen) = location(apple, kitchen).
yes

?- location(apple, kitchen) = location(pear, kitchen).
no

?- a(b,c(d,e(f,g))) = a(b,c(d,e(f,g))).
yes

?- a(b,c(d,e(f,g))) = a(b,c(d,e(g,f))).
no

在下面的例子中使用的變數,注意變數是如何繫結為某個值的。

?- X = a.
X = a

?- 4 = Y.
Y = 4

?- location(apple, kitchen) = location(apple, X).
X = kitchen

當然也可以同時使用多個變數。

?- location(X,Y) = location(apple, kitchen).
X = apple
Y = kitchen

?- location(apple, X) = location(Y, kitchen).
X = kitchen
Y = apple

變數之間也可以聯合。每個變數都對應一個Prolog的內部值。當兩個變數之間進行聯合時,Prolog就把它們標記為相同的值。在下面的例子中,我們假設Prolog使用‘_nn’,其中‘n’為數字,代表沒有繫結的變數。

?- X = Y.
X = _01
Y = _01

?- location(X, kitchen) = location(Y, kitchen).
X = _01
Y = _01

Prolog記住了被繫結在一起的變數,這將在後面的繫結中反映出來,請看下面的例子。

?- X = Y, Y = hello.
X = hello
Y = hello

?- X = Y, a(Z) = a(Y), X = hello.
X = hello
Y = hello
Z = hello

最後的這個例子能夠很好地說明Prolog的變數繫結與其他語言中的變數賦值的區別。請仔細分析下面的詢問。

?- X = Y, Y = 3, write(X).
3
X = 3
Y = 3

?- X = Y, tastes_yucky(X), write(Y).
broccoli
X = broccoli
Y = broccoli

當兩個含變數的結構之間進行聯合時,變數所取的值使得這兩個結構相同。

?- X = a(b,c).
X = a(b,c)

?- a(b,X) = a(b,c(d,e)).
X = c(d,e)

?- a(b,X) = a(b,c(Y,e)).
X = c(_01,e)
Y = _01

無論多麼複雜,Prolog都將準確地記錄下變數之間的關係,一旦某個變數繫結為某值,與之有關的變數都將改變。

?- a(b,X) = a(b,c(Y,e)), Y = hello.
X = c(hello, e)
Y = hello

?- food(X,Y) = Z, write(Z), nl, tastes_yucky(X), edible(Y), write(Z). food(_01,_02)
food(broccoli, apple)
X = broccoli
Y = apple
Z = food(broccoli, apple)

如果在兩次繫結中變數的值發生衝突,那麼目標就失敗了。

?- a(b,X) = a(b,c(Y,e)), X = hello.
no

上面的例子中,第二個子目標失敗了,因為找不到一個y的值使得hello與c(Y,e)之間能夠聯合。而下面的例子是成功的。

?- a(b,X) = a(b,c(Y,e)), X = c(hello, e).
X = c(hello, e)
Y = hello

如果變數不能繫結為某一可能的值,那麼聯合也將失敗。

?- a(X) = a(b,c).
no

?- a(b,c,d) = a(X,X,d).
no

下面的這個例子很有趣,請你研究一下吧。

?- a(c,X,X) = a(Y,Y,b).
no

你明白為什麼這個例子失敗麼?第一個引數的繫結使得Y繫結為c,第二個引數之間的繫結告訴Prolog變數X與Y的值相同,那麼X也繫結c,而最後一個引數的繫結使得X為b,有矛盾,所以失敗了。這就是說沒有什麼辦法能使得這兩個結構聯合。

匿名變數(_)不會繫結為任何值。所以也不要求它所出現的位置的值必須相同。

?- a(c,X,X) = a(,,b).
X = b

如果使用(=)那麼聯合操作時顯式的。而Prolog在使用子句與目標匹配時的聯合則是隱式的。