Recursion Can';我不明白为什么prolog会无限循环

Recursion Can';我不明白为什么prolog会无限循环,recursion,prolog,transitive-closure,Recursion,Prolog,Transitive Closure,从布拉特科的书中, 我们有以下不起作用的代码- anc4(X,Z):- anc4(X,Y), parent(Y,Z). anc4(X,Z):- parent(X,Z). 在书中,第55页的图2.15显示了父(Y,Z)一直在调用,直到堆栈内存不足 我不明白的是,prolog首先对anc4(X,Y)执行递归调用,而不是对父(Y,Z)执行递归调用。为什么prolog不一遍又一遍地转到第一行,anc4(X,Y),而是转到第二行 你能解释一下为什么总是调用parent(Y,Z)行

从布拉特科的书中, 我们有以下不起作用的代码-

anc4(X,Z):-
    anc4(X,Y),
    parent(Y,Z).
anc4(X,Z):-
    parent(X,Z).
在书中,第55页的图2.15显示了
父(Y,Z)
一直在调用,直到堆栈内存不足

我不明白的是,prolog首先对anc4(X,Y)执行递归调用,而不是对父(Y,Z)执行递归调用。为什么prolog不一遍又一遍地转到第一行
anc4(X,Y)
,而是转到第二行

你能解释一下为什么总是调用
parent(Y,Z)
行吗


谢谢。

如果没有表格机制,Prolog默认情况下无法处理左递归。只有一些Prolog系统支持tabling,通常需要显式声明哪些谓词是table的

如果您使用的是XSB、YAP或SWI Prolog,请尝试在包含
anc4/2
谓词定义的源文件顶部添加以下指令:

:- table(anc4/2).
然后重试您的查询。tabling机制检测查询何时调用自身的变量(*),并暂停该分支的执行,直到找到查询答案并尝试另一个分支(在本例中由第二个子句提供)。如果发生这种情况,则使用该答案继续执行


(*)Variant在这里表示变量重命名时两个术语相等。

您的“问题”(即目标顺序)的根源深深植根于语言的基础

Prolog基于简单而有效的时间回溯策略来实现,而左递归子句,如
anc4/2
,会导致无限递归。 实际上,逗号运算符
(,)/2
代表

仅当左表达式成立时才计算右表达式

因此,条款中目标的顺序实际上是程序的重要组成部分

对于你的具体案例

... , parent(Y,Z).
如果

anc4(X,Y), 
不起作用

与目标顺序相对应的是条款顺序

也就是说,在交换子句之后,整个程序具有不同的语义:

anc4(X,Z):-
    parent(X,Z).
anc4(X,Z):-
    anc4(X,Y),
    parent(Y,Z).

为了更好地理解这个问题,我认为也值得尝试一下这个定义。

嗨,谢谢,我不确定我是否理解什么是“表格机制”,我只是不明白为什么第二届家长会打电话来。编辑了我的答案,对表格做了简要/有限的解释。有关全面的说明,请参阅支持制表的系统手册。@Alan,制表基本上是为了提高效率而在Prolog系统中实现memonization()。@coder:实际上,制表并不像您的评论听起来那么容易。虽然它有一些便利性,但实现它需要(我认为)几个月才能成为世界顶级软件工程师之一,并且对正在发生的事情有深刻的理解。使用它需要很多经验,因为-就像约束一样-它基本上是一个@capelical,我完全同意我没有提到在Prolog中实现记忆的复杂性,实现确实是一个非常复杂的想法,我只是解释了基本思想(例如什么是tabling)从来没有说过关于实现的任何事情…
anc4(X,Z):-anc4(X,Y),…
就在那里。Prolog将继续选择第一个子句,直到它失败或成功。两者都没有。它只是不断地再次调用anc4/2。有关如何诊断此类问题,请参阅。有关定义此问题的一般方法,请参阅。