我正在编写一个程序来检查列表是否包含唯一长度的子列表:
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([]).
,现在该谓词正常工作。
答案 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真是太酷了,很优雅。