Prolog - union不检查重复项或列表是否有序

时间:2013-01-28 09:19:04

标签: prolog set set-union

我正在尝试在Prolog中编写一个union函数,但我遇到了一些麻烦。我已查找示例并列出了内置的union示例,但我正在编写自己的作业。当列表具有重复值和/或列表的顺序不提升时,我注意到一些奇怪的结果。 以下是内置的联合代码:

union([], A, A) :- !.
union([A|C], B, D) :-
        memberchk(A, B), !,
        union(C, B, D).
union([A|B], C, [A|D]) :-
        union(B, C, D).

我认为这里的伪代码是我们要查找结果中的所有列表1,一旦它耗尽,我们比较列表2和列表3.它们应该是相同的。但是,这不会检查订单。

30 ?- union([1,2,3],[],[3,2,1]).
false.

为什么这是假的?即使顺序不同,列表1和列表3也是相同的集合!

24 ?- union([a],[a,a],[a,a]).
true.

25 ?- union([a,a],[a],[a,a]).
false.

这两者有什么不同?它们应该产生相同的结果。但是,由于写入函数的方式,最后我们只比较第25行和列表3,第25行不同。

我的问题是。 。 。是否有更好的方法来编写这些函数,以便正确处理重复项并且顺序无关紧要?人们会认为内置的方法可以解决问题,但不会骰子。

3 个答案:

答案 0 :(得分:1)

首先,读取使用一致命名编写的代码更容易:

union([], A, A) :- !.
union([A|B], C, D) :-
        memberchk(A, B), !,
        union(B, C, D).
union([A|B], C, [A|D]) :-
        union(B, C, D).

它做什么?给定两个列表AB,它会生成一个结果,其中A的所有元素的前缀都不在B中,然后是B本身。所以,union([1,2,3],[],[1,2,3])。还有union([1,2,3],[2],[1,3,2])。你看到这里保留了订单。因此,如果您想比较列表而不管它们的顺序如何,您应该为此编写一个特殊的附加谓词:union([1,2,3],[],X), regardless(X,[3,2,1])应该可以正常工作。

与重复项相同 - 您的集合等式谓词应该忽略任何。 union如上所述OTOH不是关于集合,而是关于列表。有许多不同的列表代表相同的集合,但作为列表,它们被认为是不同的。

在您25中遇到重复问题:union([a,a],[a],X)生成X=[a]。同样,设置它与[a,a]相同,但作为列表它们是不同的。

应对此问题的一个策略是将表示为严格增加的列表 - 如果您的元素具有为其定义的顺序。然后我们可以编写union这样根据该定义给出两个,它也会产生一个,并且它将有效地工作:

union([],X,X):-!.
union(X,[],X):-!.
union([A|B],[C|D],[H|T]):-
  A @< C -> H=A, union(B,[C|D],T) ;
  C @< A -> H=C, union([A|B],D,T) ;
  H=A, union(B,D,T).

我们也必须在这里定义make_set/2谓词。甚至更好(在某些方面)通过自平衡二叉树来表示集合(同样,可比元素)。

答案 1 :(得分:0)

您正在使用语言(Prolog,在您的情况下)放在您手中的“工具”实施概念。然后你应该更好地定义(首先是自然语言)你的目标是什么,考虑到追加 / 3也适合联合概念。

你可以在列表 A,B之间调用列表 C union ,如果....

我会用这种方式填写省略号

  • 每个A元素在
  • 中出现一次
  • 每个B元素在
  • 中出现一次
  • 每个C元素都出现在A B

如果您同意此定义,那么实现可能是

union(A, B, C) :-
  elems_once(A, [], C1),
  elems_once(A, C1, C2),
  each_elems(C2, A, B, C).

图书馆代码显示效率低得多,但这是普遍性的代价......

答案 2 :(得分:0)

要有union(?A, ?B, ?C)(也就是说,你可以使用任何变量作为输入或输出)我创建一个新的联合

uniao(?A, ?B, ?C)

使用list:union等其他内容,如:

uniao([], [], []) :- !.

uniao(X, [], X) :- !.

uniao([], X, X) :- !.

uniao(X, Y, Z) :-
    nonvar(X),
    nonvar(Y),
    var(Z),
    list_to_set(X, Xs),
    list_to_set(Y, Ys),
    union(Xs, Ys, Z), 
    !.  

uniao(X, Y, Z) :-
    nonvar(X),
    var(Y),
    nonvar(Z),
    list_to_set(X, Xs),
    list_to_set(Z, Zs),
    subset(Xs, Zs),
    subtract(Zs, Xs, Y), 
    !.  

uniao(X, Y, Z) :-
    var(X),
    nonvar(Y),
    nonvar(Z),
    list_to_set(Y, Ys),
    list_to_set(Z, Zs),
    subset(Ys, Zs),
    subtract(Zs, Ys, X),
    !.

uniao(X, Y, Z) :-
    nonvar(X),
    nonvar(Y),
    nonvar(Z),
    list_to_set(X, Xs),
    list_to_set(Y, Ys),
    list_to_set(Z, Zs),
    union(Xs, Ys, Ts),
    subtract(Zs, Ts, []),
    subtract(Ts, Zs, []),
    !.