3
union([H|T],[],[H|T]).     
union([],[H|T],[H|T]).    
union([H|T], SET2, RESULT) :- member(H,SET2), union(T,SET2,RESULT).    
union([H|T], SET2, [H|RESULT]) :- not(member(H,SET2)), union(T,SET2,RESULT).

我能够理解它正在遍历第一个列表并根据元素是否是第二个列表的成员进行添加。我明白了逻辑。但是,工作流程对我来说很神秘,一旦第一个列表用完,它就会将“第二个列表”的元素添加到结果中。

请有人举一个简单的例子,比如union([1,2], [2,3], Result),并解释工作流程。

4

3 回答 3

7

我假设您正在调用 union/3 并实例化了第一个和第二个参数。第三个参数可以在调用时未实例化,并在返回时与两个列表的并集统一,或者如果它已经实例化,则可用于检查它是否与前两个列表的(有序)并集匹配。

第一个子句声明如果第二个参数是空列表并且第一个列表至少有一个元素,那么联合就是第一个列表。同样,第二个子句指出如果第一个参数是空列表并且第二个列表至少有一个元素,那么联合就是第二个列表。

第三个子句在第一个列表上递归并检查第二个列表以查看该项目是否已经存在。在这种情况下,它只是用第一个列表的尾部调用自己。

第四个子句测试第一个列表的头部以检查它是否不包含在第二个列表中,并使用尾部递归调用(就像第三个子句一样)。然而,在递归返回时,它将该项添加到第三个列表的头部,从而将该项添加到联合中。

请注意,在您的实现中,两个空集的并集总是会失败。您可以通过修改第一个或第二个子句以允许一个空列表来解决此问题,或者为此情况添加另一个子句。例如

union([],[],[]).

现在让我们看看当我们调用时会发生什么union([1,2],[2,3], Result)

前两个子句将无法匹配,因为它们都不是空列表。

我们进入第三个子句并检查元素 1 不是第二个列表的成员,因此在那里失败。

我们现在尝试第四个子句并测试元素 1 i 不在第二个列表中,所以我们调用union([2], [2,3], Result), 我们标记这个执行点 ( *1 )。

同样,前两个子句将无法匹配,因此我们输入第三个子句。这里我们测试元素 2 确实包含在第二个列表中,所以我们调用union([], [2,3], Result),我们标记这个执行点 ( *2 )

现在第一个子句失败了,因为第一个参数是空列表。我们现在输入第二个子句,将第三个参数与第二个列表 ([2,3]) 统一起来。

此时我们返回到 (*2),现在 Result 被实例化为 [2,3]。该子句在此结束,因此我们将第三个参数与 [1,2,3] 绑定,然后返回 ( *1 )。

我们现在在 ( *1 ) 那里 Result 并且因此第三个参数被实例化为 [1,2,3]。

这给了我们第一个结果[1,2,3]

然而,当我们在 ( *2 ) 中成功时留下了一个选择点,所以如果我们要求 Prolog 搜索另一个答案,它仍然必须尝试 union([2],[2,3], Result) 的第四个子句。

所以我们进入第四个子句来测试 2 是否不是 [2,3] 的成员失败了,所以 Prolog 会告诉我们没有其他答案。

于 2012-10-16T02:01:54.560 回答
1

您没有检查SET2,因此假设其中没有重复项,则基本递归可以是单个谓词

union([], U, U).

@gusbro 已经解释过,当H它不属于 SET2 时,它在递归调用成功后被放置在结果的(本地)前面。

解释应该可以消除您的疑虑,但请注意not/1 基本上重复了之前(失败)调用中已经执行的相同测试。那么更好的代码可能是

union([H|T], SET2, RESULT) :-
   member(H,SET2), !, % note the commit
   union(T,SET2,RESULT).    
union([H|T], SET2, [H|RESULT]) :- 
   % useless now 
   % not(member(H,SET2)),
   union(T,SET2,RESULT).

这等效于您的代码,假设member/2 没有副作用(确实如此)。

not/1 可以使用!/0 来实现。

于 2012-10-16T07:28:10.647 回答
1

对相关问题“ 2 个列表的交集和并集”的回答中,我提出了交集和并集的逻辑纯实现。

与您问题的其他答案不同,纯变体是单调的,因此在与非基本术语一起使用时在逻辑上保持合理。

于 2015-04-30T08:37:40.710 回答