我试图回答另一个问题(虽然是错误的),这导致了一个关于“差异列表”(或“列表差异”的问题,这似乎是一个更合适的名称,除非“Escherian Construction”不是首选)
我们有一个完整的基础元素列表obj(X,Y)
(包括基础X
和Y
基础)。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).
现在,这很容易使用过滤、list prepend 和 来实现reverse/2
,但是使用差异列表和list append呢?
但是,我无法使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???
更新
使用 Paulo 的代码片段:
% 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).
因此,在这种情况下,术语等价或不等价是解决方案!
我们现在通过了所有的测试。