在prolog中陷入无限循环

时间:2015-03-17 14:03:15

标签: prolog failure-slice

我希望我的程序能够找到整数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]).

然后作为检查我跑了潜艇(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])困住了。有人知道如何克服这个问题吗?

由于

2 个答案:

答案 0 :(得分:4)

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

您还应该在第3个子句中约束[B|R2],以避免重复重叠规则匹配。

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

A

答案 1 :(得分:2)

@ lurker的回答是在谓词的语义层面上。没关系。但是有一种更简单的方法可以识别问题 - 只需使用以下failure slice

subs(0,[],_X) :- false.
subs(N,[A|R1],[A|R2]):- false, N>0, N1 is N-1, subs(N1,R1,R2).
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])。但是,它应该这样做。因此,在剩余的可见部分中,您需要解决一个问题。

找到此故障切片只有一个标准:查询的(通用)非终止。没有关于实际预期含义的进一步信息用于确定该切片。