我刚刚开始学习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在进入循环之前将X
与a
统一起来,Y
与b
统一起来。
确定未终止原因的另一种方法是通过在程序中添加目标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).
变量Y
根本不用于可见部分。X
仅出现一次。 因此,r(X)
将是可能的最一般查询,因此它将具有最差的终止属性(这实际上取决于r/1
的定义)。无论如何,q/1
的论点对终止没有影响!
还有另一个属性要得出结论:子句的顺序对终止属性没有任何影响!你可以很容易地看到这一点:无论false
完全删除的子句出现在何处,都可以删除它们。
有关详细信息,请参阅故障切片。