我有一个奇怪的问题,我不知道如何解决。
我编写了一个谓词,通过删除重复项来压缩列表。
因此,如果输入为[a,a,a,a,b,c,c,a,a]
,则输出应为[a,b,c,a]
。我的第一个代码工作,但项目顺序错误。所以我添加了一个append/3
目标,它完全停止了工作。
无法弄清楚原因。我试图追踪和调试,但不知道出了什么问题。
这是我的代码有效,但项目顺序错误:
p08([Z], X, [Z|X]).
p08([H1,H2|T], O, X) :-
H1 \= H2,
p08([H2|T], [H1|O], X).
p08([H1,H1|T], O, X) :-
p08([H1|T], O, X).
这是新版本,但根本不起作用:
p08([Z], X, [Z|X]).
p08([H1,H2|T], O, X) :-
H1 \= H2,
append(H1, O, N),
p08([H2|T], N, X).
p08([H1,H1|T], O, X) :-
p08([H1|T], O, X).
答案 0 :(得分:2)
H1
不是列表,这就是append(H1, O, N)
失败的原因。
如果您将H1
更改为[H1]
,您实际上会得到与您的第一个相同的解决方案。为了真正反转累加器中的列表,您应该更改前两个参数的顺序:append(O, [H1], N)
。此外,您应该使用与空列表p08([], X, X)
匹配的第一个规则更改第一个规则(没有它,目标p08([], [], Out)
失败)。
现在,为了解决您的问题,这里是最简单的解决方案(已经是尾递归,因为@false在此答案的注释中说明,因此不需要累加器)
p([], []). % Rule for empty list
p([Head, Head|Rest], Out):- % Ignore the Head if it unifies with the 2nd element
!,
p([Head|Rest], Out).
p([Head|Tail], [Head|Out]):- % otherwise, Head must be part of the second list
p(Tail, Out).
如果你想要一个与你的相似(使用累加器):
p08(List, Out):-p08(List, [], Out).
p08([], Acc, Acc).
p08([Head, Head|Rest], Acc, Out):-
!,
p08([Head|Rest], Acc, Out).
p08([Head|Tail], Acc, Out):-
append(Acc, [Head], Acc2),
p08(Tail, Acc2, Out).
答案 1 :(得分:2)
纯粹而简单:
list_withoutAdjacentDuplicates([],[]).
list_withoutAdjacentDuplicates([X],[X]).
list_withoutAdjacentDuplicates([X,X|Xs],Ys) :-
list_withoutAdjacentDuplicates([X|Xs],Ys).
list_withoutAdjacentDuplicates([X1,X2|Xs],[X1|Ys]) :-
dif(X1,X2),
list_withoutAdjacentDuplicates([X2|Xs],Ys).
示例查询:
?- list_withoutAdjacentDuplicates([a,a,a,a,b,c,c,a,a],Xs).
Xs = [a,b,c,a] ; % succeeds, but leaves useless choicepoint(s) behind
false
以下代码基于if_/3
和reified term equality (=)/3
@false,结合第一个参数索引 - 帮助我们避免上面创建无用的选择点
list_without_adjacent_duplicates([],[]).
list_without_adjacent_duplicates([X|Xs],Ys) :-
list_prev_wo_adj_dups(Xs,X,Ys).
list_prev_wo_adj_dups([],X,[X]).
list_prev_wo_adj_dups([X1|Xs],X0,Ys1) :-
if_(X0 = X1, Ys1 = Ys0, Ys1 = [X0|Ys0]),
list_prev_wo_adj_dups(Xs,X1,Ys0).
让我们看看它的实际效果!
?- list_without_adjacent_duplicates([a,a,a,a,b,c,c,a,a],Xs).
Xs = [a,b,c,a]. % succeeds deterministically
答案 2 :(得分:2)
在这个答案中,我们使用meta-predicate foldl/4
和
Prolog lambdas
:- use_module(library(apply)).
:- use_module(library(lambda)).
我们根据if_/3
和(=)/3
定义逻辑上纯的谓词list_adj_dif/2
:
list_adj_dif([],[]).
list_adj_dif([X|Xs],Ys) :-
foldl(\E^(E0-Es0)^(E-Es)^if_(E=E0,Es0=Es,Es0=[E0|Es]),Xs,X-Ys,E1-[E1]).
让我们运行OP提供的查询!
?- list_adj_dif([a,a,a,a,b,c,c,a,a],Xs). Xs = [a,b,c,a]. % succeeds deterministically
更一般的查询怎么样?我们是否得到了我们期望的所有解决方案?
?- list_adj_dif([A,B,C],Xs).
A=B , B=C , Xs = [C]
; A=B , dif(B,C), Xs = [B,C]
; dif(A,B), B=C , Xs = [A,C]
; dif(A,B), dif(B,C), Xs = [A,B,C].
是的,我们这样做!所以... 底线是?
就像之前很多次一样,单调的if-then-else结构if_/3
使我们能够...
答案 3 :(得分:2)
更容易:
compress([X],[X]).
compress([X,Y|Zs],Ls):-
X = Y,
compress([Y|Zs],Ls).
compress([X,Y|Zs],[X|Ls]):-
X \= Y,
compress([Y|Zs],Ls).
代码工作得很好,它深入到基本情况,其中列表只包含一个元素,然后它出现,如果找到的元素等于他右边的元素,这样的元素不会添加到'Ls'列表(没有重复的列表),否则它是。
答案 4 :(得分:0)
compr([X1,X1|L1],[X1|L2]) :-
compr([X1|L1],[X1|L2]),
!.
compr([X1|L1],[X1|L2]) :-
compr(L1,L2).
compr([],[]).