List 序言:检查两个列表是否具有相同的元素

List 序言:检查两个列表是否具有相同的元素,list,prolog,non-termination,failure-slice,List,Prolog,Non Termination,Failure Slice,我是Prolog新手,在检查两个列表是否有完全相同的元素时遇到了问题。元素可能有不同的顺序。我有以下代码: myremove(X, [X|T], T). myremove(X, [H|T], [H|R]) :- myremove(X, T, R). same_elements([], []). same_elements([H1|T1], L2) :- myremove(H1, L2, Nl2), same_elements(T1, Nl2).

我是Prolog新手,在检查两个列表是否有完全相同的元素时遇到了问题。元素可能有不同的顺序。我有以下代码:

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

 same_elements([], []).
 same_elements([H1|T1], L2) :-      
    myremove(H1, L2, Nl2),  
    same_elements(T1, Nl2).
除了

?- same_elements([b,c,a], X).
返回第一个结果后导致内存不足错误。因此,我试图通过检查列表的长度是否相等以及检查H1是否是L2的成员来缩小结果集:

mylength([], 0).
mylength([_|T], R) :-
   mylength(T, Nr),
   R is Nr+1.

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

same_elements([], []).
same_elements([H1|T1], L2) :- 
   mylength([H1|T1], X),
   mylength(L2, Y),
   Y = X,
   mymember(H1, L2),
   myremove(H1, L2, Nl2),
   same_elements(T1, Nl2).
现在两者

?- same_elements([b,c,a], X).
?- same_elements(X, [b,c,a]). 
返回所有的结果,但它们只是挂在最后。有更好的方法吗

简短回答:是的

但是,在讨论这个问题之前,有一个更有趣的问题:你是如何发现这些问题的?你找到他们一定很幸运!我试过:

?- same_elements([a,b,c,d,e,f,g],Xs). Xs = [a, b, c, d, e, f, g] ; Xs = [a, b, c, d, e, g, f] ; Xs = [a, b, c, d, f, e, g] ; Xs = [a, b, c, d, g, e, f] ; ... 现在,我们将永远看不到任何解决方案。但我们可能会观察到查询的终止。唉,这个查询现在可能会循环。至少我们不再费力地寻找不相关的解决方案

为了进一步缩小不终止的原因,我们将在您的计划中添加
false
目标。修改后的程序称为故障片。通过这种方式,我们试图缩小不终止的责任范围。如果我们成功地添加了
false
目标,这样程序仍然不会终止,那么我们将有一个很好的解决问题的线索。例如:

same_elements([], []). same_elements([H1|T1], L2) :- mylength([H1|T1], X), false, mylength(L2, Y), Y = X, mymember(H1, L2), myremove(H1, L2, Nl2), same_elements(T1, Nl2). 所以,我们已经删除了太多。下一次尝试:

same_elements([], []). same_elements([H1|T1], L2) :- mylength([H1|T1], X), mylength(L2, Y), false, Y = X, mymember(H1, L2), myremove(H1, L2, Nl2), same_elements(T1, Nl2). 也不是为了

?- same_elements(Xs,[a,b,c,d,e,f,g]).
而罪魁祸首只是这个计划的一小部分

您的想法是确保两个列表的长度相同

定义一个新的长度谓词,而不是使用长度谓词:

list_same_length([], []). list_same_length([_|Xs], [_|Ys]) :- list_same_length(Xs, Ys). 列出相同的长度([],[])。 列表长度相同([|Xs],|Ys]):- 列出相同的长度(Xs,Ys)。
现在,“双向”终止。

你可以使用内置的:
相同的元素(X,Y):-msort(X,S),msort(Y,S)。
我不知道为什么@false说我的答案是个错误的建议。现在我把它删除了。无论如何……你知道Prolog有什么用吗?当我尝试你的建议时,相同的_元素([b,c,a],X)只返回一个结果,但我想要所有结果。@chac:看到我的答案了吗:你建议在可见部分之外更改一些内容。因此,您的切割将不会产生任何影响。@chac:请查看下面的失败切片。但要说得很清楚:通过在myremove/3中添加一个cut,程序会像以前一样循环!谢谢我不知道那个调试技术,现在我的谓词终止了。@CarolineM:您可能还想只测试一次相同长度的参数,然后使用原始定义,使两个参数的长度相同。
?- same_elements([a,b,c,d,e,f,g],Xs).
?- same_elements(Xs,[a,b,c,d,e,f,g]).
list_same_length([], []). list_same_length([_|Xs], [_|Ys]) :- list_same_length(Xs, Ys).