Prolog程序以任何顺序查找两个列表的相等性

时间:2010-04-26 00:11:45

标签: list prolog any failure-slice

我想编写一个Prolog程序来查找两个列表的相等性,其中元素的顺序为 无所谓。所以我写了以下内容:

del(_, [], []) .
del(X, [X|T], T).  
del(X, [H|T], [H|T1]) :-
   X \= H,
   del(X, T, T1).

member(X, [X|_]).  
member(X, [_|T]) :- 
   member(X, T).

equal([], []).  
equal([X], [X]).  
equal([H1|T], L2) :-
   member(H1, L2),
   del(H1, L2, L3),
   equal(T, L3).  

但是,当我提供equal([1,2,3],X).之类的输入时,它并未显示X的所有可能值。相反,程序挂在中间。可能是什么原因?

9 个答案:

答案 0 :(得分:7)

isSubset([],_).
isSubset([H|T],Y):-
    member(H,Y),
    select(H,Y,Z),
    isSubset(T,Z).
equal(X,Y):-
    isSubset(X,Y),
    isSubset(Y,X).

答案 1 :(得分:4)

尝试使用谓词来检查其中一个集合是否是其他集合的排列:

delete(X, [X|T], T).

delete(X, [H|T], [H|S]):-
    delete(X, T, S).


permutation([], []).

permutation([H|T], R):-
    permutation(T, X), delete(H, R, X).

(谓词取自http://www.dreamincode.net/code/snippet3411.htm

?- permutation([1,2,3],[3,1,2]).
true 

答案 2 :(得分:3)

您观察到的非终止的实际原因是:以下条款不以任何方式,形状或形式约束L2

equal([H1|T], L2) :- 
   member(H1, L2),
   del(H1, L2, L3),
   equal(T, L3).

因此,您的查询?- equal([1,2,3], X).意味着证明目标member(_, L2)不会普遍终止。因此,equal([1,2,3], X)也不能普遍终止!

有关如何解释Prolog代码不终止的更多信息,请阅读

PS。从不同的角度看待终止问题,我们发现在这种情况下,非终止事实上是必要的结果

为什么呢?因为您不限制多重性的数量,这使得解决方案的大小设置为无限。该集合不能用有限数量的答案表示(假设您不允许延迟目标)。

答案 3 :(得分:2)

如果你不关心列表元素的多重性, 检查是否有足够的实例化 ground/1, 执行它 iwhen/2, 并使用sort/2消除重复项,如下所示:

same_elements(As, Bs) :-
   iwhen(ground(As+Bs), (sort(As,Es),sort(Bs,Es))).

使用SWI Prolog 8.0.0进行示例:

?- same_elements([a,c,c,b,a,c], [c,b,b,a]).
true.

?- same_elements([a,b,b,a], [b,a,b,e]).
false.

?- same_elements([a,b,b,a], Xs).
ERROR: Arguments are not sufficiently instantiated

答案 4 :(得分:1)

试试这个:

equal([],[]).
equal([Ha|Ta],[Hb|Tb]) :-
   Ha = Hb, lequal(Ta,Tb).

答案 5 :(得分:1)

怎么样:

equal(X, Y) :-
    subtract(X, Y, []),
    subtract(Y, X, []).

答案 6 :(得分:1)

那么为什么equal([1,2,3], X)不能与您的代码一起终止呢?

让我们看看代码的!什么是故障片?这是标记信息:

  

failure-slice是通过添加一些目标false获得的Prolog程序的片段。失败切片有助于本地化纯粹单调Prolog程序的普遍不终止的原因。它们还有助于给出所需推论数量的下限。这是一种具体的技术。

创建失败切片:

  • 我们将false目标插入到程序中
  • 同时确保片段不会以上述目标终止。
del(_, [], [])  :- false.
del(X, [X|T], T) :- false.
del(X, [H|T], [H|T1]) :- false,
   dif(X, H),                    % note that the OP originally used `X \= H`
   del(X, T, T1).

member(X, [X|_]).  
member(X, [_|T]) :- 
   member(X, T).

equal([], []) :- false.
equal([X], [X]) :- false.
equal([H1|T], L2) :-
   member(H1, L2), false,
   del(H1, L2, L3),
   equal(T, L3).  

?- equal([1,2,3], _), false.     % note that `false` is redundant ...
** LOOPS **                      % ... as above `equal/2` cannot succeed.

那么......上面的失败片告诉我们什么?它说:

  • 使目标equal([1,2,3], X)普遍终止......
  • ...我们必须更改至少其中一个剩余部分(不是 striked-through )!

答案 7 :(得分:0)

我建议使用内置谓词msort/2,然后比较列表。它需要在SWI Prolog上花费O(nlogn)时间,而逐个元素地检查未分类列表将需要O(n 2 )时间。

lists_equal(List1, List2) :-
    msort(List1, Sorted1),
    msort(List2, Sorted2),
    Sorted1=Sorted2.

这里,排序列表需要O(nlogn)时间,并且比较它们需要在SWI Prolog上花费O(n)时间,我不知道其他实现。

答案 8 :(得分:-1)

简言之

equal([],[]).
equal([H|T],[H|T1]):-equal(T,T1).