2015-11-02 143 views
1

我對Prolog完全陌生,我無法理解這段代碼。你會如何閱讀這4個子句?他們在做什麼?這段代碼是什麼意思?

a([]). 
a([_|L]):-b(L). 

b([_]). 
b([_|L]):-a(L). 

謝謝。

+2

運行一些查詢的[標籤:序言,頂層]!查詢如'? - a(Xs).'或'? - b(Xs).' ... – repeat

+1

當您擁有偶數個元素的列表時,它似乎會成功。 – Enigmativity

+0

@Enigmativity它取決於你的意思。 'a'在偶數列上成功,'b'在奇數列上成功。它效率低下(在任何給定列表的幾乎所有情況下都會成功兩次)。 – lurker

回答

1

由於@Repeat在他的評論暗示,運行一般查詢,這裏是你得到的:

| ?- a(Xs). 

Xs = [] ? ; 

Xs = [_,_] ? ; 

Xs = [_,_] ? ; 

Xs = [_,_,_,_] ? ; 

Xs = [_,_,_,_] ? ; 

Xs = [_,_,_,_,_,_] ? ; 

Xs = [_,_,_,_,_,_] ? ; 
... 

A ND:

| ?- b(Xs). 

Xs = [_] ? ; 

Xs = [_] ? ; 

Xs = [_,_,_] ? ; 

Xs = [_,_,_] ? ; 

Xs = [_,_,_,_,_] ? ; 

Xs = [_,_,_,_,_] ? ; 

Xs = [_,_,_,_,_,_,_] ? ; 

Xs = [_,_,_,_,_,_,_] ? ; 
... 

所以a(Xs)成功如果Xs爲含有偶數個元素的列表,和b(Xs)成功如果Xs是含有奇數個的參數的列表。正如你所看到的,a/1b/1在每種情況下成功兩次,除了a([]).只成功一次。所以它不是確定列表長度奇偶性的有效謂詞。

讓我們重新編寫這些更多的描述性名稱:

even([]). 
even([_|L]) :- odd(L). 
odd([_]). 
odd([_|L]) :- even(L). 

現在讓我們來「讀」他們在說什麼:

  1. []爲偶數列表
  2. [_|L]爲偶數列表,如果L是奇怪名單
  3. [_]是一個奇怪的名單
  4. [_|L]是一個奇怪的列表,如果L是偶列表

這些聽起來合乎邏輯,但爲什麼even/1odd/1even([])異常成功兩次?如果您查看odd/1的定義,則有兩種方法可以成功執行[_]。一個是通過odd([_]).條款。第二種是由第二odd/1,因爲你會:

odd([_|[]]) :- even([]). % [_] == [_|[]] 

由於兩個even/1odd/1電話(與even([]).除外)最終遞歸下降到呼叫odd([_]),你會得到兩種解決方案。


消除邏輯含糊不清的一種方法是對它們進行一些重構。考慮以下遞歸規則:

  • 如果列表的尾部在第一個2之後也是偶數,則至少包含2個元素的列表具有偶數個元素。
  • 如果列表的尾部在第一個2之後也是奇數,那麼至少包含2個元素的列表具有奇數個元素。

把這些規則的Prolog,包括基本情況爲前:

even([]). 
even([_,_|L]) :- even(L). 
odd([_]). 
odd([_,_|L]) :- odd(L). 

現在的結果將是:

| ?- even(Xs). 

Xs = [] ? ; 

Xs = [_,_] ? ; 

Xs = [_,_,_,_] ? ; 

Xs = [_,_,_,_,_,_] ? ; 
... 

而且

| ?- odd(Xs). 

Xs = [_] ? ; 

Xs = [_,_,_] ? ; 

Xs = [_,_,_,_,_] ? ; 
... 

繼CapelliC的建議使用DCG,可以寫成類似的規則:

even --> [] | [_,_], even. 
odd --> [_] | [_,_], odd. 

有了結果:

| ?- phrase(even, L). 

L = [] ? ; 

L = [_,_] ? ; 

L = [_,_,_,_] ? ; 
... 

而且

| ?- phrase(odd, L). 

L = [_] ? ; 

L = [_,_,_] ? ; 

L = [_,_,_,_,_] ? ; 
... 


繼@虛假的建議,一個更直接的 「修復」 的原代碼將是消除冗餘基地 odd([_]).的情況,因爲它已經被 even([]).的基本情況所涵蓋了。這也比上述s簡單一些因爲它利用了 even/1odd/1謂詞之間的相互依賴性(在上面的解決方案中, even/1odd/1獨立存在)。

even([]). 
even([_|L]) :- odd(L). 
odd([_|L]) :- even(L). 

或者,在DCG:

even --> [] | [_], odd. 
odd --> [_], even. 
+0

並得出結論?你離開它沒有幫助! – false

+0

@false - 我完全相信,我回答了OP的兩個問題(*你會如何閱讀這4個子句?*和*他們做了什麼?*)。我將詳細說明一個更好的方法來確定列表大小的平等,但根據這些問題的具體措辭,我不清楚OP的結果。 – lurker

+0

有一個更簡單的方法來刪除冗餘!只要刪除'b([_])'' – false

1

的說法架構是非常重要的:

一)名單顯然是一個計數器,因爲我們從來不考慮的內容。

B)只是一個建議:讀邏輯生產,或DCG

a-->[];[_],b. 
b-->[_];[_],a. 

被稱爲 - 例如

?- phrase(a, [w,h,a,t]).