Простой Пролог удалить из списка
(Это не вопрос курсовой работы. Просто мое личное обучение.)
Я пытаюсь выполнить упражнение в Прологе, чтобы удалить элементы из списка. Вот мой код:
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H==X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :- deleteall(T,X,Result).
Когда я проверяю его, я сначала получаю хороший ответ (т. Е. Со всеми удаленными X). Но затем при возврате мне предлагаются все другие варианты списка с некоторыми или ни с одним удаленным экземпляром X.
Почему это должно быть? Почему случаи, когда H==X когда-либо проваливаются до последнего предложения?
2 ответа
В последнем пункте говорится, что при удалении X
из списка может остаться элемент head (независимо от его значения). Prolog может использовать это предложение в любое время, когда сочтет нужным, независимо от того, является ли условие в предыдущем предложении верным или нет вернуться к этому предложению, если другое предложение не выполнено, или если вы указываете это сделать (например, путем выдачи ;
на верхнем уровне, чтобы получить следующее решение). Если добавить условие, что элемент head может не совпадать X
, он должен работать.
Редактировать: Удалено неверное утверждение, которое я первоначально открыл.
Когда вы используете (==)/2
для сравнения вам понадобится обратное в третьем правиле, т.е. (\==)/2
, С другой стороны, такое определение уже не является чистым отношением. Чтобы увидеть это, рассмотрим deleteall([X],Y,Zs), X = Y.
Для чистого отношения нам нужно (=)/2
а также dif/2
, Многие прологи, такие как SWI, YAP, B, SICStus, предлагают dif/2
,
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H=X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :-
dif(H,X),
deleteall(T,X,Result).
Посмотрите на ответы для deleteall([X,Y],Z,Xs)
!
Изменить (через четыре года):
Более эффективно, но в том же духе, это можно записать с помощью if_/3
а также (=)/3
:
deleteall([], _X, []).
deleteall([E|Es], X, Ys0) :-
if_( E = X, Ys0 = Ys, Ys0 = [E|Ys] ),
deleteall(Es, X, Ys).