以下内容基于我对“
列表中去除重复项(Prolog)”问题的
先前回答;基本思想又来源于
A U B U C 的 Prolog 并集问题的
@false的回答。
我想要传达什么信息给你?
- 您可以使用逻辑纯度来描述Prolog中所需的内容。
- 使用
if_/3
和(=)/3
,逻辑纯实现可以同时具有以下特点:
- 高效(仅在需要时留下选择点)
- 单调(在一般化/特化方面逻辑上正确)。
- @false谓词
if_/3
和(=)/3
的实现确实在内部使用元逻辑Prolog功能,但(从外部)表现为逻辑纯。
下面的list_list_intersection/3
和list_list_union/3
实现使用list_item_isMember/3
和list_item_subtracted/3
,这些函数在之前的答案中定义:
list_list_union([],Bs,Bs).
list_list_union([A|As],Bs1,[A|Cs]) :-
list_item_subtracted(Bs1,A,Bs),
list_list_union(As,Bs,Cs).
list_list_intersection([],_,[]).
list_list_intersection([A|As],Bs,Cs1) :-
if_(list_item_isMember(Bs,A), Cs1 = [A|Cs], Cs1 = Cs),
list_list_intersection(As,Bs,Cs).
以下是您在问题中发布的查询:
?- list_list_intersection([1,3,5,2,4],[6,1,2],Intersection).
Intersection = [1, 2].
让我们尝试其他的东西...以下两个查询应该在逻辑上等价:
?- A=1,B=3, list_list_intersection([1,3,5,2,4],[A,B],Intersection).
A = 1,
B = 3,
Intersection = [1, 3].
?- list_list_intersection([1,3,5,2,4],[A,B],Intersection),A=1,B=3.
A = 1,
B = 3,
Intersection = [1, 3] ;
false.
那么...最终结论是什么?
- 使用纯代码很容易保持逻辑的正确性。
- 而不纯的代码则往往表现得像“它应该做的那样”,但在像上面展示的查询中显示出各种非逻辑行为。
编辑2015-04-23
list_list_union(As,Bs,Cs)
和list_list_intersection(As,Bs,Cs)
都不能保证Cs
不包含重复元素。如果这让您感到困扰,需要适当修改代码。
以下是一些更多的查询(及其答案),当中As
和/或Bs
包含重复元素:
?- list_list_intersection([1,3,5,7,1,3,5,7],[1,2,3,1,2,3],Cs).
Cs = [1, 3, 1, 3].
?- list_list_intersection([1,2,3],[1,1,1,1],Cs).
Cs = [1].
?- list_list_union([1,3,5,1,3,5],[1,2,3,1,2,3],Cs).
Cs = [1, 3, 5, 1, 3, 5, 2, 2].
?- list_list_union([1,2,3],[1,1,1,1],Cs).
Cs = [1, 2, 3].
?- list_list_union([1,1,1,1],[1,2,3],Cs).
Cs = [1, 1, 1, 1, 2, 3].
编辑2015-04-24
为了完整起见,以下是如何强制要求交集和并集为集合---即不包含任何重复元素的列表。
以下代码非常直观:
list_list_intersectionSet([],_,[]).
list_list_intersectionSet([A|As1],Bs,Cs1) :-
if_(list_item_isMember(Bs,A), Cs1 = [A|Cs], Cs1 = Cs),
list_item_subtracted(As1,A,As),
list_list_intersectionSet(As,Bs,Cs).
list_list_unionSet([],Bs1,Bs) :-
list_setB(Bs1,Bs).
list_list_unionSet([A|As1],Bs1,[A|Cs]) :-
list_item_subtracted(As1,A,As),
list_item_subtracted(Bs1,A,Bs),
list_list_unionSet(As,Bs,Cs).
请注意,
list_list_unionSet/3
基于
list_setB/2
,在
这里 定义。
现在让我们看看
list_list_intersectionSet/3
和
list_list_unionSet/3
的实际应用:
?- list_list_unionSet([1,2,3,1,2,3,3,2,1],[4,5,6,2,7,7,7],Xs).
Xs = [1, 2, 3, 4, 5, 6, 7].
?- list_list_intersectionSet([1,2,3,1,2,3,3,2,1],[4,5,6,2,7,7,7],Xs).
Xs = [2].
编辑于2019-01-30
以下是从@GuyCoder的评论中提取的一个额外的查询(以及两个变体):
?- list_list_unionSet(Xs,[],[a,b])。
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
...
?- list_list_unionSet([],Xs,[a,b])。
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
...
?- list_list_unionSet(Xs,Ys,[a,b])。
Xs = [],Ys = [a,b]
; Xs = [],Ys = [a,b,b]
; Xs = [],Ys = [a,b,b,b]
...
使用旧版本的list_item_subtracted/3
,上述查询不存在终止。
使用新版本后它们会终止。由于解集大小是无限的,因此这些查询都不会普遍终止。