Я попытался ответить на другой вопрос (хотя и ошибочно), и это привело к вопросу о «списках различий» (или «списках различий», которое кажется более подходящим, если только «Эшеровская конструкция» не является предпочтительной)
У нас есть полностью заземленный список элементов obj(X,Y)
(оба X
и Y
ground). Мы хотим сохранить только первое obj(X,_)
, где X
еще не встречалось при просмотре списка спереди назад. Эти «первые элементы» должны появляться в порядке появления в результате.
Давайте уточним проблему с помощью тестовых случаев:
% Testing
:- begin_tests(collapse_dl).
test(one) :- collapse_dl([],[]).
test(two) :- collapse_dl([obj(a,b)],
[obj(a,b)]).
test(three) :- collapse_dl([obj(a,b),obj(a,c)],
[obj(a,b)]).
test(four) :- collapse_dl([obj(a,b),obj(a,c),obj(b,j)],
[obj(a,b),obj(b,j)]).
test(five) :- collapse_dl([obj(a,b),obj(a,c),obj(b,j),obj(a,x),obj(b,y)],
[obj(a,b),obj(b,j)]).
:- end_tests(collapse_dl).
rt :- run_tests(collapse_dl).
Теперь это легко реализовать с помощью фильтрации, добавления к списку и reverse/2
, но как насчет использования списков различий и список приложений ?
однако я не могу заставить работать предикат seen/2
. Он проверяет, есть ли obj(A,_)
в списке различий. Но каково правильное завершение для этого предиката?
% This is called
collapse_dl([],[]) :- !.
collapse_dl([X|Xs],Out) :-
Dlist = [X|Back]-Back, % create a difflist for the result; X is surely in there (as not yet seen)
collapse_dl(Xs,Dlist,Out). % call helper predicate
% Helper predicate
collapse_dl([],Ldown,Lup):- % end of recursion; bounce proper list back up
Ldown = Lup-[]. % the "back" of the difflist is unified with [], so "front" becomes a real list, and is also Lup
collapse_dl([obj(A,_)|Objs],Ldown,Out) :-
seen(obj(A,_),Ldown), % guard: already seen in Ldown?
!, % then commit
collapse_dl(Objs,Ldown,Out). % move down chain of induction
collapse_dl([obj(A,B)|Objs],Ldown,Out) :-
\+seen(obj(A,_),Ldown), % guard: not yet seen in Ldown?
!, % then commit
Ldown = Front-Back, % decompose difference list
Back = [obj(A,B)|NewTail], % NewTail is fresh! Append via difflist unification magic
collapse_dl(Objs,Front-NewTail,Out). % move down chain of induction; Front has been refined to a longer list
% Membership check in a difference list
seen(obj(A,_),[obj(A,_)|_Objs]-[]) :- !. % Yup, it's in there. Cut retry.
seen(Obj,[_|Objs]-[]) :- ... % But now???
Обновление
С помощью фрагмента кода Пауло:
% Membership check in a difference list
seen(Element, List-Back) :-
List \== Back,
List = [Element|_].
seen(Element, List-Back) :-
List \== Back,
List = [_| Tail],
seen(Element, Tail-Back).
Итак, эквивалентность терминов , или неэквивалентность в этом случае, является решением!
Теперь мы пройдем весь тест.