我才刚刚开始学习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).
答案 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
,因为在进入循环之前,序言将X
与a
和Y
与b
统一。
答案 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).
在可见部分根本没有使用变量Y
。 X
仅出现一次。因此,r(X)
将是可能的最通用查询,因此它将具有最差的终止属性(实际上取决于r/1
的定义)。无论如何,q/1
的参数对终止没有影响!
还有另一个属性可以得出结论:子句的顺序对终止属性没有任何影响!您可以轻松地看到这一点:无论用 false
完全删除的条款出现在什么地方,都可以删除它们。
有关更多信息,请参见failure-slice。