2013-07-23 83 views
2

我剛剛「學習」了序言,我真的不明白什麼是輸入以及函數中的輸出是什麼。在序言中的輸出或輸入

例如

concatenate([X|L1], L2, [X|L3]) = concatenate (L1,L2,L3). 
concatenate([],L,L). 

這是什麼意思?

If I write 
?- concatenate(X,[2,Y],[1,1,1,2,3]) 

返回

X=[1,1,1], 
Y=3. 

因此,這意味着第三個參數是第1次和2d的串聯,但我們如何通過閱讀函數的聲明知道這一點? 感謝

回答

3

只是補充臺現有優秀的答案...

在Prolog,你沒有想到的事情爲「功能」與參數的輸入和輸出(雖然他們行爲是那樣),而是作爲「謂詞「定義規則,並將嘗試實例化任何變量參數(未經實例化的變量),以使規則成立。這個過程可能會導致沒有解決方案,一個解決方案或許多解決方案,並且您將全部獲得。並非所有的謂詞都爲未經證實的變量的每個組合提供了這種「全部功能」,或者如果太多的變量沒有被證實,那麼提供解決方案在邏輯上就變得不切實際。在任何這些情況下決定參數的行爲,以及謂詞是否有任何解決方案,都是謂詞的邏輯,而不是任何正式的輸入或輸出聲明。

讓我們以給定的concatenate爲例(注意我使用的是GNU Prolog)。謂詞concatenate(L1, L2, L3)的含義是「L1與L2連接(按此順序)給出L3」,這比說「給定L1和L2提供它們在L3中的級聯」更普遍,這意味着特定的輸入和輸出。

所以,如果我進入:

concatenate([1,2], [3,4], L3). 

我得到:

L3 = [1,2,3,4] 

(1 ms) yes 
| ?- 

這意味着序言找到一個解決方案與L3所示實例謂語。我還可以輸入:

concatenate(L1, [3,4], [1,2,3,4]). 

而且我會得到:

L1 = [1,2] 

(1 ms) yes 
| ?- 

這意味着序言找到一個解決方案與L1所示實例謂語。同樣如果我輸入concatenate([1,2], L2, [1,2,3,4])我會得到一個解決方案:L2 = [3,4]

讓我們嘗試一些更有趣:

concatenate(L1, L2, [1,2,3,4]). 

的Prolog會發現這個解決方案,但我已經提供了兩個非實例變量。因此,解決方案將涉及這些可能性:

L1 = [1,2,3,4] 
L2 = [] ? ; 

L1 = [1,2,3] 
L2 = [4] ? ; 

L1 = [1,2] 
L2 = [3,4] ? ; 

L1 = [1] 
L2 = [2,3,4] ? ; 

L1 = [] 
L1 = [1,2,3,4] ? ; 

(1 ms) yes 
| ?- 

現在讓我們試試這個:

concatenate([1,2], L2, L3). 

我得到:

L3 = [1,2|L2] 

| ?- 

在這種情況下,爲L2,因此可能性, L3是無界的,所以序言顯示了一個通用的解決方案。

在你的例子中,concatenate(X, [2,Y], [1,1,1,2,3])適用同樣的想法。Prolog將嘗試找到滿足條件的XY的實例,滿足條件:「與[2,Y]連接的X給出[1,1,1,2,3]」,[2,Y]是帶有第一個元素的列表2和第二元素Y。在這種情況下,您只有一個解決方案。

由於關於這一主題的變化,使用@DrH描述列表的概念,如果你這樣做:

concatenate(X, [2|Y], [1,1,1,2,3]). 

你會得到X = [1,1,1]Y = [3]。請注意,如果你這樣做:

concatenate(X, [2,Y], [1,1,1,2,3,4]). 

你得到「沒有」(沒有解決),因爲Y在此處顯示爲一個原子,而不是(因爲逗號語法)的列表。換句話說,沒有兩個元素列表看起來像[2,Y],當與X的任何可能性連接時將產生[1,1,1,2,3,4]。但是,如果你這樣做:

concatenate(X, [2|Y], [1,1,1,2,3,4]). 

你會得到X = [1,1,1]Y = [3,4]因爲我現在顯示未初始化Y以列表的尾部,它本身就是一個列表,而不是隻是一個原子(使用|語法)。

正如@WillNess指出的那樣,給定謂詞的文檔將告訴您如果讓某些變量沒有實際意義,就希望預測謂詞的行爲。一篇寫得好的序言式謂詞比起那些寫得不好或者限制較多的序言更有可能「做你期望或想要做的事」。這不會使限制性較強的謂詞「不好」,因爲它可能有一個非常有用的目的。它不會有用。在編寫自己的序言謂詞時,需要考慮這些事情。 Prolog就像Go的遊戲:一些簡單的規則,但很多有趣的可能性。

1
concatenate([X|L1], L2, [X|L3]) :- 
    concatenate(L1, L2, L3). 

首先,在序言列表由一個頭(這裏X)和尾(列表,這裏L1L3的其餘部分)的。所以這個謂詞表示有一個列表,其第一個元素是X,如果將它與L2連接起來,則會得到一個列表,其第一個元素也是X,而其尾部是L3。爲了使這個謂詞爲真,謂詞concatenate(L1, L2, L3)也不會失敗,也就是說,第一個列表的其餘部分可以與第二個列表連接,並且它們將導致第三個列表。

由於參數既可以是輸入變量也可以是輸出變量,因此可以使用未知變量調用此謂詞,或者如果您有三個列表,則可以通過連接其他兩個列表來檢查是否可以通過連接其他兩個列表來創建它們。

第二個謂詞concatenate([], L, L)表示如果第一個列表爲空,則連接的結果是第二個列表。

L1[1, 2, 3]L2[4, 5, 6]。讓我們打電話給我們的謂詞,看看裏面會發生什麼:

concatenate(L1, L2, L3). 
concatenate([1, 2, 3], [4, 5, 6], L3). // First predicate can be matched 
concatenate([1 | [2, 3]], [4, 5, 6], [1 | A1]). // Now [2, 3] is L1 and A1 is the current L3 

concatenate([2, 3], [4, 5, 6], A1). // First predicate can be matched 
concatenate([2 | [3]], [4, 5, 6], [2 | A2]). // Now [3] is L1 and A2 is L3 

concatenate([3], [4, 5, 6], A2). // First predicate can be matched 
concatenate([3 | []], [4, 5, 6], [3 | A3]). // Now [] is L1 and A3 is L3 

concatenate([], [4, 5, 6], A3). // Second predicate can be matched 
concatename([], [4, 5, 6], [4, 5, 6]). 

我們有一個退出條件,一個沒有body的謂詞。現在我們往回走(這叫做回溯,在搜索空間後退)。讓我們來代替A *變量的結果:

concatenate([], [4, 5, 6], [4, 5, 6]). 

concatenate([3 | []], [4, 5, 6], [3 | [4, 5, 6]]). 

concatenate([3], [4, 5, 6], [3, 4, 5, 6]). 

concatenate([2 | [3]], [4, 5, 6], [2 | [3, 4, 5, 6]]). 

concatenate([2, 3], [4, 5, 6], [2, 3, 4, 5, 6]). 

concatenate([1 | [2, 3]], [4, 5, 6], [1 | [2, 3, 4, 5, 6]]). 

concatenate([1, 2, 3], [4, 5, 6], [1, 2, 3, 4, 5, 6]). 
2

應該有與謂詞期望他們做什麼的每個參數的說明註釋:要預設(因此可以作爲輸入),是免費(尚未設置,用於輸出),或沒有偏好(因此可以是兩者)。

查看documentation for SWI Prolog - 4.1 Notation of Predicate Descriptions。他們使用

  • +爲完全實例化參數
  • -參數必須是未結合的,將用於輸出
  • ?正確類型的部分實例化參數(注意,非實例變量爲任何類型的局部術語)。

和其他幾個更高級的選項。

有時候源代碼和你的例子一樣簡單,它可以被認爲是不言而喻的,哪個是哪個。