停止Prolog中的无限循环

时间:2020-04-11 04:13:20

标签: list prolog infinite-loop

我正在尝试返回列表中的不同项目。我提出了以下代码。使用member(X,Y)检查列表的成员时,我似乎遇到了问题,并且陷入了无限循环。

get_unique(Y, [H|T]) :-
   memberchk(H, Y)->  get_unique(Y, T) ; get_unique([H|T], T).
get_unique(_, []) :- true.

final_list(X, L) :-
   get_unique(Y, L), member(X,Y).

有两种输入方式:

?- final_list(dog,[dog,cat,bat,dog]). 

true;
true;
true;
true;
(infinitely)

在这种情况下,我希望只是

true;
false.

另一种输入方式:

?- final_list(X,[dog,cat,bat,dog]).

X = dog;
X = cat;
X = bat;
true ;
true ;
true ;
true ;
true ;
true ;
(infinitely)

在这种情况下,我希望只是

X = dog;
X = cat;
X = bat;
false.

我尝试进行一些调试,我想我可以看到member(X,Y)正在生成无限循环-跟踪下面显示的步骤。我不知道如何阻止它,这样成员一旦返回bat就停止检查。

X = bat ;
   Redo: (9) lists:member(_6632, [dog, cat, bat|_6882]) ? creep
   Exit: (9) lists:member(_6632, [dog, cat, bat, _6632|_6888]) ? creep
   Exit: (8) final_list(_6632, [dog, cat, bat, dog]) ? creep
true ;
   Redo: (9) lists:member(_6632, [dog, cat, bat, _6886|_6888]) ? creep
   Exit: (9) lists:member(_6632, [dog, cat, bat, _6886, _6632|_6894]) ? creep
   Exit: (8) final_list(_6632, [dog, cat, bat, dog]) ? creep
true ;
   Redo: (9) lists:member(_6632, [dog, cat, bat, _6886, _6892|_6894]) ? creep
   Exit: (9) lists:member(_6632, [dog, cat, bat, _6886, _6892, _6632|_6900]) ? creep
   Exit: (8) final_list(_6632, [dog, cat, bat, dog]) ? creep
true ;
   Redo: (9) lists:member(_6632, [dog, cat, bat, _6886, _6892, _6898|_6900]) ? creep
   Exit: (9) lists:member(_6632, [dog, cat, bat, _6886, _6892, _6898, _6632|...]) ? creep
   Exit: (8) final_list(_6632, [dog, cat, bat, dog]) ? creep
true ;

谢谢!

1 个答案:

答案 0 :(得分:2)

单独尝试get_unique/2

?- get_unique(Y,[dog,cat,bat,dog]).
   Y = [dog,cat,bat|_A].
%                   ^^^

因此,Y只是一个部分列表,而不是(真实)列表。它包含具有三个或更多元素的所有列表。

第二个子句应读为get_unique([], []).,以避免出现此问题。而且第一个也需要重新排列:

get_unique(Y, [H|T]) :-
   ( memberchk(H, T) ->  get_unique(Y, T) ; Y = [H|Y1], get_unique(Y1, T) ).
%                 ^^                        ^^^^^^^^^^             ^^
get_unique([], []).

但是,您的定义仍然有一些奇怪的假设:

?- final_list(X,[dog,Cat]).
   X = dog, Cat = dog.

因此它迫使变量成为一个特定值。

除了重新考虑member/2之外,没有解决之道。有关干净的解决方案,请参见this answer。这是memberd/2产生的答案:

?- memberd(X,[dog,Cat]).
   X = dog
;  X = Cat, dif(Cat,dog)
;  false.

所以答案是:X = dog和以前一样,X = Cat,但前提是Catdog不同。