Stuck on an infinite loop in prolog

核能气质少年 提交于 2019-12-10 17:38:04

问题


I'd like my program to find me all sub-sets of size K of the integers 1,2,...,N.

For this, I wrote the following subs(N,X,Y) means that X is a sub-set of size N of the set Y. I defined the following:

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]).

And then as a check I ran subs(2,X,[1,2,3,4]).

I got the first answer [1,2], but never did it give a second answer, as it got stuck in an infinite loop. I tried to trace it, and seems that after finding the first answer it does:

   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]) ? 

So I see that I get stuck with subs(0, _G619, [4]). Does someone have an idea of how to overcome this problem?

Thanks


回答1:


Your 4th clause has a flaw. The head of the second argument (the subset) has a variable A which is singleton. The clause basically reads, [A|R1] is a subset of N values from [B|R2] if R1 is a subset of N values from [B|R2], for any variable A. That wouldn't be a correct rule for a subset, and results in the infinite loop since it doesn't ultimately reduce to the base case. It's not clear what the purpose of this rule is. You can probably just remove it as the first 3 adequately define the subset.

You also should constrain N in the 3rd clause to avoid duplicate overlap of rule matching.

That plus a little variable clean-up makes your predicate into:

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).



回答2:


@lurker's answer is on the semantic level of the predicate. That's fine. But there is an even simpler way of identifying the problem - simply by using at the following 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.

Already this fragment does not terminate for subs(2,X,[1,2,3,4]). However, it should do so. So in the remaining visible part there is a problem you need to address.

There is a single criterion to find this failure slice: The (universal) non-termination of your query. No further information about the actual intended meaning is used to determine this slice.



来源:https://stackoverflow.com/questions/29101117/stuck-on-an-infinite-loop-in-prolog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!