我正在尝试编写一个谓词,在Prolog中给出以下列表:
[[1,a,b],[2,c,d],[[3,e,f],[4,g,h],[5,i,j]],[6,k,l]]
将生成以下列表:
[[6,k,l],[[5,i,j],[4,g,h],[3,e,f]],[2,c,d],[1,a,b]]
如您所见,我希望保留最低级别元素的顺序,以1,a,b和NOT b,a,1的顺序生成元素。
我还想保留列表的深度,也就是说,最初嵌套的列表会以相反的顺序返回。
我已设法使用以下代码实现所需的顺序,但深度丢失,即列表不再正确嵌套:
accRev([F,S,T],A,R) :- F \= [_|_], S \= [_|_], T \= [_|_],
accRev([],[[F,S,T]|A],R).
accRev([H|T],A,R) :- accRev(H,[],R1), accRev(T,[],R2), append(R2,R1,R).
accRev([],A,A).
rev(A,B) :- accRev(A,[],B).
我很感激帮助纠正代码以保持列表的正确嵌套。谢谢!
答案 0 :(得分:0)
两个建议。首先,这是一个(rev_lists/2
),它使用了一堆SWI-PROLOG内置函数:
rev_lists(L, RL) :-
forall(member(M, L), is_list(M)), !,
maplist(rev_lists, L, L0),
reverse(L0, RL).
rev_lists(L, L).
这个通过测试列表L
的所有元素本身是否为列表(M
)来工作。如果是这样,它将递归地将自己(通过maplist
)应用于所有单个子列表,否则它将返回相同的列表。这具有所需的效果。
其次,这里再次rev_lists/2
,但是这样写的除了member/2
之外它不依赖于内置函数(这很常见):
rev_lists(L, RL) :-
reversible_list(L), !,
rev_lists(L, [], RL).
rev_lists(L, L).
rev_lists([], Acc, Acc).
rev_lists([L|Ls], Acc, R) :-
( rev_lists(L, RL), !
; RL = L
),
rev_lists(Ls, [RL|Acc], R).
reversible_list(L) :-
is_a_list(L),
\+ (
member(M, L),
\+ is_a_list(M)
).
is_a_list([]).
is_a_list([_|_]).
它基本上是相同的策略,但是使用累加器在每个级别建立反向列表,如果它们仅由列表组成;否则,返回相同的列表。