我假设您正在调用 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 会告诉我们没有其他答案。