唯一长度的子列表

时间:2012-02-19 23:48:08

标签: prolog

我正在编写一个程序来检查列表是否包含唯一长度的子列表:

e.g。 diffLengthLists([[2],[3,4]])应该返回true,而diffLengthLists([[3],[4]])应该返回false。

这是我的代码:

diffLengthLists(A):- is_list(A),
                     diffLength(A,[_]).

diffLength([A|B], [C|D]):- length(A, C), 
                           diffLength(B, D), 
                           unique([C|D]).

unique([A|B]):- \+member(A, B), unique(B).
unique([]).

所以我基本上将每个子列表的长度添加到另一个列表[C|D],然后检查[C|D]中的元素是否唯一。

但是,我的程序无法按预期方式工作。我在这做错了什么?是否有更好(更清晰)的方式来编写这个程序?

提前感谢您的帮助!

编辑:我测试了帮助器谓词,问题似乎来自diffLength但是,我不明白为什么它不起作用。 我在代码中添加了unique([]).,现在该谓词正常工作。

2 个答案:

答案 0 :(得分:3)

diffLengthLists(Xss) :-
   maplist(length,Xss,Ls),
   alldifferent(Ls).

alldifferent([]).
alldifferent([E|Es]) :-
   maplist(=\=(E),Es),
   alldifferent(Es).

如果已知所有列表的所有长度,则此解决方案终止。这就是你的家庭作业。

但是当diffLengthLists([[],[],_])失败时它不会终止。要完成一个在所有可能情况下终止的实现是非常困难的。

在SWI中,以下是预定义的,因此无需定义它。但其他系统需要它:

maplist(_Cont_1, []).
maplist( Cont_1, [A|As]) :-
   call(Cont_1, A),
   maplist(Cont_1, As).

对于maplist/3,请参阅this post

这是另一种解决方案,终止于上述目标:

diffLengthLists([]).
diffLengthLists([L|Ls]) :-
   maplist(diffLength(L),Ls),
   diffLengthLists(Ls).

diffLength([], [_|_]).
diffLength([_|_], []).
diffLength([_|Es], [_|Fs]) :-
   diffLength(Es, Fs).

找出这个谓词没有终止的情况,它应该失败!

答案 1 :(得分:2)

现在你有时间去咀嚼它并想出一个解决方案,这是攻击它的另一种方式。

我总是试着用简单的英语说明解决方案是什么,然后编写代码。在这种情况下:

如果子列表的长度不是包含列表其余部分长度的列表成员,则

'uniqll为真

uniqll([],[]).

uniqll([H|T], [LenH|LensSoFar]) :-
  uniqll(T, LensSoFar),
  length(H, LenH),
  not(member(LenH, LensSoFar)).

如果不清楚它发生了什么,那么prolog'trace'谓词就是你的朋友......事实上,当你试图为你做一些肮脏的工作/想出一个最小的解决方案时,这是最重要的。

[trace] 10 ?-  uniqll([[2,3],[4,5]],X).
   Call: (6) uniqll([[2, 3], [4, 5]], _G1276) ? creep
   Call: (7) uniqll([[4, 5]], _G1360) ? creep
   Call: (8) uniqll([], _G1363) ? creep
   Exit: (8) uniqll([], []) ? creep
   Call: (8) length([4, 5], _G1362) ? creep
   Exit: (8) length([4, 5], 2) ? creep
^  Call: (8) not(member(2, [])) ? creep
^  Exit: (8) not(user:member(2, [])) ? creep
   Exit: (7) uniqll([[4, 5]], [2]) ? creep
   Call: (7) length([2, 3], _G1359) ? creep
   Exit: (7) length([2, 3], 2) ? creep
^  Call: (7) not(member(2, [2])) ? creep
^  Fail: (7) not(user:member(2, [2])) ? creep
   Fail: (6) uniqll([[2, 3], [4, 5]], _G1276) ? creep
false.

为了成功:

[trace] 11 ?-  uniqll([[2,3],[4]],X).         
   Call: (6) uniqll([[2, 3], [4]], _G1479) ? creep
   Call: (7) uniqll([[4]], _G1560) ? creep
   Call: (8) uniqll([], _G1563) ? creep
   Exit: (8) uniqll([], []) ? creep
   Call: (8) length([4], _G1562) ? creep
   Exit: (8) length([4], 1) ? creep
^  Call: (8) not(member(1, [])) ? creep
^  Exit: (8) not(user:member(1, [])) ? creep
   Exit: (7) uniqll([[4]], [1]) ? creep
   Call: (7) length([2, 3], _G1559) ? creep
   Exit: (7) length([2, 3], 2) ? creep
^  Call: (7) not(member(2, [1])) ? creep
^  Exit: (7) not(user:member(2, [1])) ? creep
   Exit: (6) uniqll([[2, 3], [4]], [2, 1]) ? creep
X = [2, 1].

作为副作用,列表为True时,末尾的列表是长度列表。

Prolog真是太酷了,很优雅。