Prolog 初学者:仅反向列表一次
Prolog Beginner: Reverse List only once
假设我有两个任意列表,表示 3 位谓词的前两项:
[anna,berta,charlotte],[charles,bob,andy]
我想匹配第三个列表中的每个项目(3 位谓词的第三个项目),如下所示:
[[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 的新手,目前对此感到困惑。任何帮助将不胜感激。
照你说的做:反转列表一次,然后使用反转的列表。
lists_pairs(Ps1, Ps2, Pairs) :-
reverse(Ps2, RPs2),
pairs_keys_values(Pairs, Ps1, RPs2).
您可以在任何合适的 Prolog 库中查看 reverse/2
和 pairs_keys_values/3
的源代码,了解它是如何定义的。
示例查询和回答:
?- lists_pairs([anna,berta,charlotte], [charles,bob,andy], Ps).
Ps = [anna-andy, berta-bob, charlotte-charles].
我把将这些对转换为不合理的 "pair as list" 表示作为练习。
解决只需要应用一次规则的问题的诀窍是构建一个辅助规则,在调用递归规则后 and/or 之前执行额外的步骤:
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
规则重命名以避免与包含辅助步骤的 "top" match/3
规则冲突。
这是 的小跟进。
为了在某些情况下帮助终止,您可以添加一个冗余的 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).
假设我有两个任意列表,表示 3 位谓词的前两项:
[anna,berta,charlotte],[charles,bob,andy]
我想匹配第三个列表中的每个项目(3 位谓词的第三个项目),如下所示:
[[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 的新手,目前对此感到困惑。任何帮助将不胜感激。
照你说的做:反转列表一次,然后使用反转的列表。
lists_pairs(Ps1, Ps2, Pairs) :-
reverse(Ps2, RPs2),
pairs_keys_values(Pairs, Ps1, RPs2).
您可以在任何合适的 Prolog 库中查看 reverse/2
和 pairs_keys_values/3
的源代码,了解它是如何定义的。
示例查询和回答:
?- lists_pairs([anna,berta,charlotte], [charles,bob,andy], Ps).
Ps = [anna-andy, berta-bob, charlotte-charles].
我把将这些对转换为不合理的 "pair as list" 表示作为练习。
解决只需要应用一次规则的问题的诀窍是构建一个辅助规则,在调用递归规则后 and/or 之前执行额外的步骤:
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
规则重命名以避免与包含辅助步骤的 "top" match/3
规则冲突。
这是
为了在某些情况下帮助终止,您可以添加一个冗余的 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).