为什么我会得到一个无限循环(Prolog)



我刚刚开始学习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).

正如评论中所说,循环是由r/1引起的。为了说明原因,yust 键入?- 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派生。您还可以看到此问题以进行更深入的解释。

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

确定未终止原因的另一种方法是通过在程序中添加目标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),falser(Y).

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

还有另一个属性要得出结论:子句的顺序对终止属性没有任何影响!你可以很容易地看到这一点:无论false完全删除的子句出现在何处,都可以删除它们。

有关详细信息,请参阅故障切片。