Prolog无限循环循环事实

Prolog Infinite loop on circular facts

这是我的循环部分(定义人与人之间的关系):

connection(harry, ron).
connection(ron, harry).
connection(hermione, harry).

我想直接或通过其他人使用递归找出是否存在联系。

这段代码在上面的情况下陷入死循环:

connected(A, B) :-
   connection(A, B).
connected(A, B) :- 
   connection(A, C),
   connected(C, B).

我希望递归在遇到以前的搜索时停止。 例如:

?- connected(hermione, X).
X = harry ;
X = ron.

谢谢!

Prolog 的执行机制非常不直观。它将递归(正如您从其他语言中了解到的那样)与回溯相结合。但是有一个很好的出路。您可以考虑使用更小的程序来代替原来的程序。

为了更好地理解实际的循环,这里是称为 的最小程序片段,它是未终止的原因。其中有一些额外的伪造:一些目标 false。有了这些目标,推理的数量就会减少(或保持不变)。因此,当生成的程序循环时,这也是您的原始程序循环的原因。

connection(harry, ron).
connection(ron, harry).
connection(herminone, harry) :- false.

connected(A, B) :- false, connection(A, B).
connected(A, B) :-
    connection(A, C),
    connected(C, B), false.

?- connected(A, B).

查询仍在循环。请注意,当询问合适的人(我想你知道是谁)时,它会失败(并因此终止):

?- connected(tom, B).
   false.

要解决这个问题,最简单的方法是像这样使用closure/3

connected(A, B) :-
   closure(connection, A, B).

您可以尝试制表。许多 Prolog 系统都有 table/1 指令。您只需将它放在要制表的谓词之前。

:- table connected/2.
connected(A, B) :-
   connection(A, B).
connected(A, B) :- 
   connection(A, C),
   connected(C, B).

如果你接着运行一个查询,递归会自动停止。这是一个示例 运行,其中包含 SWI-Prolog 表格:

Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

?- connected(hermione, X).
X = harry ;
X = ron.