为什么会出现无限循环(序言)

时间:2019-06-03 18:32:40

标签: prolog infinite-loop

我才刚刚开始学习Prolog,并开始尝试。现在我陷入了困境。当我请求时,我编写的程序陷入了无限循环

?- q(b).

,我不明白为什么要这么做。如果有人可以向我解释这将是很好的。

p(a).    
p(b).
q(Y) :- r(X), r(Y).    
r(X) :- r(f(X)).    
r(a) :- p(c).    
r(a) :- p(a).    
r(b) :- p(b).

2 个答案:

答案 0 :(得分:4)

如评论中所述,该循环是由r/1引起的。要显示原因,请键入?- trace, q(b).查看跟踪信息(现在忽略单例警告):

 Call:q(b)
 Call:r(_4244)
 Call:r(f(_4162))
 Call:r(f(f(_4162)))
 Call:r(f(f(f(_4162))))
 Call:r(f(f(f(f(_4162)))))
 Call:r(f(f(f(f(f(_4162))))))
 Call:r(f(f(f(f(f(f(_4162)))))))
 Call:r(f(f(f(f(f(f(f(_4162))))))))

现在您可以看到它尝试派生r/1进入循环。您也可以看到this question进行更深入的说明。

请注意,在序言中,条款的顺序很重要。只需将r(X) :- r(f(X)).行放在程序底部即可。现在尝试?- q(b).在第一个答案上,您会得到true,因为在进入循环之前,序言将XaYb统一。

答案 1 :(得分:1)

识别不终止原因的另一种方法是通过在程序中添加目标 false 来减少程序将执行的推理次数:

q(Y) :- r(X), false, r(Y).

r(X) :- r(f(X)), false.
r(a) :- false, p(c).
r(a) :- false, p(a).
r(b) :- false, p(b).

?- q(Y).
** LOOPS **

由于该程序仍在循环,因此您将需要在可见部分中进行修改。请注意,已经完全删除了多少东西!无论如何定义p/1,这个问题都会持续存在。

如果您仔细观察q/1,就会发现问题之一:

q(Y) :- r(X), false, r(Y).

在可见部分根本没有使用变量YX仅出现一次。因此,r(X)将是可能的最通用查询,因此它将具有最差的终止属性(实际上取决于r/1的定义)。无论如何,q/1的参数对终止没有影响!

还有另一个属性可以得出结论:子句的顺序对终止属性没有任何影响!您可以轻松地看到这一点:无论用 false 完全删除的条款出现在什么地方,都可以删除它们。

有关更多信息,请参见