2015-11-24 54 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