_
就像任何其他變量,除了你看到的每個變量被視爲一個不同的變量,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] ;
希望這有助於!
我很困惑這是如何工作的。 沒有我指定通配符是什麼,我不認爲它會工作。 它可能是它的工作原理,因爲當涉及到connectRow謂詞它匹配通配符與R? – Shookie
是的,它將'_'與'R'結合在一起。但是在Prolog中的統一與你的標準參數傳遞完全不同。 –
感謝您的回覆,我現在明白了。當你說不一樣/發送鏈接時,你能擴展你的意思嗎? – Shookie