2015-11-24 51 views
5

假設我有一個代表3元謂詞的前兩項的任意兩個名單:Prolog的初學者:反向列表只有一次

[anna,berta,charlotte],[charles,bob,andy] 

我想在第三列表(每個項目的第三項匹配如下:

[[anna,andy],[berta,bob],[charlotte,charles]] 

基本上,這些項目按照順序相反的方式進行匹配。爲了配合以順序方式的項目,我已經設計了下面的代碼:

match([],[],[]). 
match([A|At],[C|Ct],[[A,C]|Dt]):-match(At,Ct,Dt). 

但是,這會給我的以下內容:

match([anna,berta,charlotte],[charles,bob,andy],X). 
X=[[anna,charles],[berta,bob],[charlotte,andy]] 

所以我需要以某種方式扭轉第二個列表。到目前爲止,我已經改變了代碼如下:

match([],[],[]). 
match([A|At],[C|Ct],[[A,B]|Dt]):-reverse([C|Ct],[B|Bt]),match(At,Bt,Dt). 

但這將不斷逆轉與各循環中的第二個列表。結果將如下所示:

match([anna,berta,charlotte],[charles,bob,andy],X). 
X=[[anna,andy],[berta,charles],[charlotte,bob]] 

問題: 如何扭轉第二隻列出一次,所以實際結果匹配所需的嗎?或者我的方法存在根本性缺陷?我是prolog的新手,目前受此阻礙。任何幫助,將不勝感激。

回答

2

訣竅解決需要你的問題應用規則只有一次是建立執行和/或調用遞歸規則前後額外的步驟,輔助規則:

match(A, B, R) :- reverse(B, RevB), match_impl(A, RevB, R). 

match_impl([], [], []). 
match_impl([A|At], [C|Ct], [[A,C]|Dt]) :- match_impl(At, Ct, Dt). 

match_impl/3是你match/3規則重新命名以避免與包含輔助步驟的「頂部」match/3規則衝突。

3

完全按照您的說法操作:顛倒一次列表,然後使用反轉列表。

lists_pairs(Ps1, Ps2, Pairs) :- 
    reverse(Ps2, RPs2), 
    pairs_keys_values(Pairs, Ps1, RPs2). 

您可以檢查出的reverse/2pairs_keys_values/3的源代碼在任何像樣的Prolog庫,看看它是如何定義的。

樣品的查詢和答案:

?- lists_pairs([anna,berta,charlotte], [charles,bob,andy], Ps). 
Ps = [anna-andy, berta-bob, charlotte-charles]. 

我離開轉換成對等的非理智「對作爲名單」表示作爲一個練習。

+0

S(X)的使用乾淨的數據表示。 – repeat

2

這是一個小的後續@mat's answer

爲了幫助結束在某些情況下,你可以添加一個冗餘same_length_as/3目標,像這樣:

 
lists_pairs(Ps1, Ps2, Pairs) :- 
    same_length_as(Ps1, Ps2, Pairs), 
    reverse(Ps2, RPs2), 
    pairs_keys_values(Pairs, Ps1, RPs2). 

輔助謂詞same_length_as/3可以這樣定義:

same_length_as([],[],[]). 
same_length_as([_|As],[_|Bs],[_|Cs]) :- 
    same_length_as(As,Bs,Cs). 
+1

'maplist(\ _^_^_^true,Ps1,Ps2,Pairs)' – false