Остановка бесконечного л oop в Прологе - PullRequest
0 голосов
/ 11 апреля 2020

Я пытаюсь вернуть отдельные элементы в списке. Я придумал следующий код. Кажется, я сталкиваюсь с проблемой при проверке членов списка с помощью member (X, Y), и он сталкивается с бесконечным l oop.

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.

Я попытался выполнить некоторую отладку, и я думаю, что я вижу, что член (X, Y) генерирует бесконечную трассировку l oop - шаги видно ниже. Я не знаю, как это остановить, так что член перестает проверять, как только он возвращает биты.

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 Ответ

2 голосов
/ 11 апреля 2020

Попробуйте 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.

Таким образом, переменные становятся единым заданным значением c.

Нет чистого выхода из этого, кроме пересмотра member/2. См. этот ответ для получения чистого решения. Вот ответ memberd/2:

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

Таким образом, ответ говорит: X = dog как и прежде, X = Cat, но только если Cat отличается от dog.

...