循环事实的Prolog无限循环

时间:2019-03-25 15:03:29

标签: prolog transitive-closure failure-slice

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

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.

谢谢!

2 个答案:

答案 0 :(得分:3)

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).

答案 1 :(得分:0)

您可以尝试制表。许多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.