【问题标题】:Sub-lists of Unique Length唯一长度的子列表
【发布时间】:2015-12-10 22:40:08
【问题描述】:

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

例如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([]).,现在谓词可以正常工作了。

【问题讨论】:

  • 您是否尝试评估您的辅助谓词(diffLengthunique)以查看它们的实现是否符合您的期望?
  • 我完全忘记了,谢谢你提到它。我更新了问题。
  • 听起来您发现了一个缺失的基本案例。一个好主意是始终确保退化案例适用于所有谓词定义。一旦您对那里感到满意,您可能会考虑在脑海中浏览一些示例案例,以了解为什么它们没有按预期出现? (此外,您从未提及为什么您认为它们不起作用。您是否确定了谓词没有给出正确答案的值?)
  • 感谢您的帮助。我弄清楚了问题所在:) 我会在几个小时内发布答案。 (基本上我只需要为 diffLength 添加另一个基本案例,以及其他一些小的编辑)

标签: prolog


【解决方案1】:
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).

找出这个谓词不终止的情况,什么时候应该失败!

【讨论】:

  • 实际上我对代码所做的更改解决了这个问题,(并为您提供的示例返回 false,正如预期的那样)。 “这就是你的作业是关于什么的”,你怎么知道我的作业“是”关于什么的?大声笑
  • (我会单独评论你的代码)但是对于家庭作业问题:编写一个在没有解决方案的所有情况下都会终止的定义肯定远远超出了家庭作业。
  • @Amino Acid:您的代码仍然无法工作 - 我没有看到任何重大变化。 IE。您对diffLengthLists([[]]) 的定义仍然不成功。
  • diffLengthLists([[a],[a,b|_]]). 应该成功(或循环),但不能失败。您的实施失败了。
  • 最小的反例是diffLengthLists([[],_]).,应该成功或循环,但不能失败。
【解决方案2】:

现在你已经有时间仔细研究它并想出一个解决方案,这是另一种攻击它的方法。

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

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

uniqll([],[]).

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

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

[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 真是太酷太优雅了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 1970-01-01
    • 2014-07-05
    • 1970-01-01
    • 1970-01-01
    • 2023-01-21
    相关资源
    最近更新 更多