2013-01-23 31 views
0

我遇到這樣的代碼:這個通配符在這個prolog場景中做了什麼?

connectRow(_,_,0). 
connectRow([spot(_,R,_,_)|Spots],R,K) :- K1 is K-1, connectRow(Spots,R,K1). 

/*c*/ 
connectRows([]). 
connectRows(Spots) :- 
    connectRow(Spots,_,9), 
    skip(Spots,9,Spots1), 
    connectRows(Spots1). 

如何通配符在connectRow(斑點,_,9)工作?它如何知道要檢查哪些值以及它如何知道它檢查了所有可能的值?

編輯:我想我理解爲什麼這個工作,但我想如果有人可以驗證這個對我來說: 當我用通配符「connect」connectRow它匹配通配符與connectRow中的「R」謂詞。這可能嗎?

回答

2

_就像任何其他變量,除了你看到的每個變量被視爲一個不同的變量,Prolog不會告訴你它與什麼它統一。那裏沒有特別的行爲;如果它讓你對這種行爲感到困惑,那麼只需創造一個全新的變量,並將它放在那裏看看它的作用。

讓我們來談談Prolog如何處理變量。這裏有一個實驗,如果你碰巧擁有它們,那麼它可能會破壞無用的先入爲主的觀念。

?- length([2,17,4], X) 
X = 3. 

很多的Prolog看起來是這樣的,很容易陷入思維,有被指定爲「出」的作用就像返回值和「中」的作用就像參數變量指定變量的陷阱。畢竟:

?- length([2,17,4], 3). 
true. 

?- length([2,17,4], 5). 
false. 

在這裏,我們開始看到有趣的事情正在發生。一個錯誤的直覺是,Prolog會以某種方式跟蹤輸入和輸出變量,並在這種情況下「檢查」。但這並不是什麼事情,因爲統一比這更普遍。注意:

?- length(X, 3). 
X = [_G2184, _G2187, _G2190]. 

現在,我們已經顛覆了傳統的參數/返回值:序言知道,X是一個列表三個項目長,但不知道是什麼項目實際上是。信不信由你,當你知道你需要多少,但是你不需要單獨命名它們時,這種技術經常用於生成變量。

?- length(X, Y). 
X = [], 
Y = 0 ; 

X = [_G2196], 
Y = 1 ; 

X = [_G2196, _G2199], 
Y = 2 ; 

X = [_G2196, _G2199, _G2202], 
Y = 3 

它發生的長度的定義是非常普遍的,Prolog可以用它來生成列表及其長度。這種行爲是Prolog非常擅長「生成和測試」解決方案的一部分。您可以從邏輯上定義問題,Prolog應該能夠生成邏輯上合理的值以進行測試。

所有這些變化從長度的一個非常簡單的定義彈簧:

length([], 0). 
length([_|Rest], N1) :- 
    length(Rest, N0), 
    succ(N0, N1). 

的關鍵是計算長度像一個過程不讀這個,而是把它看作名單和數量之間的邏輯關係。該定義是歸納性的,將空列表與0相關聯,列表中的某些項目與1 +列表中其餘部分的長度相關。使這項工作的引擎被稱爲統一。

在第一種情況下,length([2,17,4], X),值[17,4]與Rest一起統一,N0與2統一,N1與3統一。該過程是遞歸的。在最後一種情況下,X與[]和Y統一爲0,這自然會導致下一個我們有一些項目並且Y是1的情況,並且表示列表中項目的變量沒有任何東西尤其是統一與無關緊要,因爲該變量的值從未被使用過。

看着你的問題,我們看到了同樣的遞歸結構。謂詞相當複雜,所以讓我們把它們分成幾部分。

connectRow(_, _, 0). 

這是說connectRow(X, Y, 0)是真實的,不管X和Y這是基本情況。

connectRow([spot(_, R, _, _)|Spots], R, K) :- 

此規則相匹配的特定結構的點的列表,假定所述第一點的第二值(R)的第二參數相匹配。

K1 is K-1, connectRow(Spots, R, K1). 

本節的主體基本上重複上遞減K,第三個參數。

現在很清楚,這基本上會生成一個長度爲K = [spot(_, R, _, _), spot(_, R, _, _), ... spot(_, R, _, _)]的列表,並且spot的其他三個位置中沒有特殊值。事實上,這就是我們測試時看到的:

?- connectRow(X, Y, 0). 
true ; 
(infinite loop)^CAction (h for help) ? abort 
% Execution Aborted 

?- connectRow(X, Y, 2). 
X = [spot(_G906, Y, _G908, _G909), spot(_G914, Y, _G916, _G917)|_G912] ; 
(infinite loop)^CAction (h for help) ? abort 

所以這裏似乎有一些錯誤;如果我確信這是故事的全部,我會說:

  • 基本情況應該使用空列表,而不是匹配任何
  • 我們應該在感性的情況下規定,K> 0
  • 我們應該使用clpfd如果我們希望能夠產生所有的可能性

使我們體驗到不同的變化:

:- use_module(library(clpfd)). 

connectRow([], _, 0). 
connectRow([spot(_, R, _, _)|Spots], R, K) :- 
    K #> 0, K1 #= K-1, connectRow(Spots, R, K1). 

?- connectRow(X, Y, 0). 
X = [] ; 
false. 

?- connectRow(X, Y, 1). 
X = [spot(_G906, Y, _G908, _G909)] ; 
false. 

?- connectRow(X, Y, Z). 
X = [], 
Z = 0 ; 

X = [spot(_G918, Y, _G920, _G921)], 
Z = 1 ; 

X = [spot(_G918, Y, _G920, _G921), spot(_G1218, Y, _G1220, _G1221)], 
Z = 2 

您會注意到,在結果中,我們有Y站在我們的spot結構中,但我們有奇怪的自動生成的變量在其他位置,如_G918。當它發生時,我們可以使用_,而不是Y和看到類似的效果:

?- connectRow(X, _, Z). 
X = [], 
Z = 0 ; 

X = [spot(_G1269, _G1184, _G1271, _G1272)], 
Z = 1 ; 

X = [spot(_G1269, _G1184, _G1271, _G1272), spot(_G1561, _G1184, _G1563, _G1564)], 
Z = 2 

所有這些奇形怪狀的變量都在那裏,因爲我們使用_。請注意,所有spot結構在第二個位置的生成變量完全相同,因爲Prolog被告知必須將connectRow的第二個參數與第二個位置spot統一。這是無處不在的,因爲R是遞歸地傳遞給connectRow的下一個調用。

希望這有助於解釋您的示例中_會發生什麼情況,以及一般情況下的Prolog統一。

編輯:統一的東西有R

要回答以下你的問題,你可以直接或通過其綁定到一個變量,使用變量統一用R值。例如,我們可以直接將其綁定:

?- connectRow(X, 'Hello, world!', 2). 
X = [spot(_G275, 'Hello, world!', _G277, _G278), spot(_G289, 'Hello, world!', _G291, _G292)] 

我們也可以綁定,然後後來分配給它:

?- connectRow(X, R, 2), R='Neato'. 
X = [spot(_G21, 'Neato', _G23, _G24), spot(_G29, 'Neato', _G31, _G32)], 
R = 'Neato' 

有什麼特別的話R=<foo>;它統一了表達式的兩邊,但雙方可以是表達式,而不是變量:

?- V = [2,3], [X,Y,Z] = [1|V]. 
V = [2, 3], 
X = 1, 
Y = 2, 
Z = 3. 

所以,你可以在另一個謂語用[R一樣好:

?- connectRow(X, R, 2), append([1,2], [3,4], R). 
X = [spot(_G33, [1, 2, 3, 4], _G35, _G36), spot(_G41, [1, 2, 3, 4], _G43, _G44)], 
R = [1, 2, 3, 4] ; 

注意,這對於創造了機會回溯並生成其他解決方案。例如:

?- connectRow(X, R, 2), length(R, _). 
X = [spot(_G22, [], _G24, _G25), spot(_G30, [], _G32, _G33)], 
R = [] ; 

X = [spot(_G22, [_G35], _G24, _G25), spot(_G30, [_G35], _G32, _G33)], 
R = [_G35] ; 

X = [spot(_G22, [_G35, _G38], _G24, _G25), spot(_G30, [_G35, _G38], _G32, _G33)], 
R = [_G35, _G38] ; 

希望這有助於!

+0

我很困惑這是如何工作的。 沒有我指定通配符是什麼,我不認爲它會工作。 它可能是它的工作原理,因爲當涉及到connectRow謂詞它匹配通配符與R? – Shookie

+0

是的,它將'_'與'R'結合在一起。但是在Prolog中的統一與你的標準參數傳遞完全不同。 –

+0

感謝您的回覆,我現在明白了。當你說不一樣/發送鏈接時,你能擴展你的意思嗎? – Shookie