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在使用子句與目標匹配時的聯合則是隱式的。