我正在尝试在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行不同。
我的问题是。 。 。是否有更好的方法来编写这些函数,以便正确处理重复项并且顺序无关紧要?人们会认为内置的方法可以解决问题,但不会骰子。
答案 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).
它做什么?给定两个列表A
和B
,它会生成一个结果,其中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 ,如果....
我会用这种方式填写省略号
如果您同意此定义,那么实现可能是
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, []),
!.