【问题标题】:Stuck on an infinite loop in prolog卡在序言中的无限循环
【发布时间】:2015-03-18 00:55:34
【问题描述】:

我希望我的程序找到整数 1,2,...,N 的所有大小为 K 的子集。

为此,我写了以下 subs(N,X,Y) 表示 X 是集合 Y 的大小为 N 的子集。我定义了以下内容:

subs(0,[],X).
subs(N,[A|R1],[A|R2]):-N>0, N1 is N-1, subs(N1,R1,R2).
subs(N,[A|R1],[B|R2]):-subs(N,[A|R1],R2).
subs(N,[A|R1],[B|R2]):-subs(N,R1,[B|R2]).

然后作为检查,我运行了 subs(2,X,[1,2,3,4])。

我得到了第一个答案 [1,2],但它从未给出第二个答案,因为它陷入了无限循环。我试图追踪它,似乎在找到第一个答案之后:

   Redo: (8) subs(0, _G613, [3, 4]) ? creep
^  Call: (9) 0>0 ? creep
^  Fail: (9) 0>0 ? creep
   Redo: (8) subs(0, _G613, [3, 4]) ? creep
   Call: (9) subs(0, [_G618|_G619], [4]) ? creep
^  Call: (10) 0>0 ? creep
^  Fail: (10) 0>0 ? creep
   Redo: (9) subs(0, [_G618|_G619], [4]) ? creep
   Call: (10) subs(0, [_G618|_G619], []) ? creep
   Fail: (10) subs(0, [_G618|_G619], []) ? creep
   Redo: (9) subs(0, [_G618|_G619], [4]) ? creep
   Call: (10) subs(0, _G619, [4]) ? creep
   Exit: (10) subs(0, [], [4]) ? creep
   Exit: (9) subs(0, [_G618], [4]) ? creep
   Exit: (8) subs(0, [_G618], [3, 4]) ? creep
   Exit: (7) subs(1, [2, _G618], [2, 3, 4]) ? 

所以我发现我被subs(0, _G619, [4]) 卡住了。有人知道如何克服这个问题吗?

谢谢

【问题讨论】:

  • 您的第 4 条有缺陷。第二个参数(子集)的头部有一个变量A,它是单例的。该子句基本上是这样的,对于任何变量A,如果R1 是来自[B|R2]N 值的子集,则[A|R1] 是来自[B|R2]N 值的子集 .这不是子集的正确规则。目前尚不清楚这条规则的目的是什么。

标签: prolog failure-slice


【解决方案1】:

您的第 4 条有缺陷。第二个参数(子集)的头部有一个变量A,它是单例的。该子句的基本内容是,对于任何变量A,如果R1 是来自[B|R2]N 值的子集,则[A|R1] 是来自[B|R2]N 值的子集 .对于子集,这不是正确的规则,并且会导致无限循环,因为它最终不会减少到基本情况。目前尚不清楚这条规则的目的是什么。您可能可以将其删除,因为前 3 个充分定义了子集。

您还应该在第三条子句中限制N,以避免规则匹配的重复重叠。

加上一点变量清理,你的谓词变成:

subs(0, [], _).
subs(N, [A|R1], [A|R2]) :- N > 0, N1 is N-1, subs(N1, R1, R2).
subs(N, R1, [_|R2]) :- N > 0, subs(N, R1, R2).

【讨论】:

  • 谢谢!但是现在它起作用了,我注意到了一些事情:如果我要求 subs(K,[1,2],[1,2,3]) 我收到以下错误:错误:未处理的异常:> / 2:参数不够实例化,但如果我要求 subs(2,X,[1,2,3]) 一切正常(我得到 X=[1,2] , X=[1,3] 和 X=[2,3] )。似乎是一个奇怪的错误?
  • @TheEmeritus 这是因为数字关系运算符(例如 >/2)要求所有参数都被完全实例化。不能有任何变量让它能够工作。如果您希望您的 subs 谓词是完全相关的并允许第一个参数是变量的情况,则需要对其进行一些重构以处理这种情况。在 Prolog 中,为可变参数情况的子集制作谓词通常很容易,但要使其完全相关可能是一个巨大的挑战。
【解决方案2】:

@lurker 的答案是关于谓词的语义级别。没关系。但是还有一种更简单的方法来识别问题 - 只需使用以下failure slice

subs(0,[],_X) :- falsesubs(N,[A|R1],[A|R2]):- false, N>0, N1 为 N-1, subs(N1,R1,R2) s>。 subs(N,[A|R1],[_B|R2]):- false, subs(N,[A|R1],R2)。 subs(N,[_A|R1],[B|R2]):- subs(N,R1,[B|R2]), false

对于subs(2,X,[1,2,3,4]),这个片段已经没有终止。但是,它应该这样做。所以在剩下的可见部分有一个问题你需要解决。

只有一个标准可以找到这个失败片段:查询的(通用)不终止。没有关于实际预期含义的更多信息用于确定此切片。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-11
    • 2018-03-27
    • 1970-01-01
    • 2020-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多