这是我的事实的循环部分(定义人与人之间的关系):
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.
谢谢!
答案 0 :(得分:3)
Prolog的执行机制非常不直观。它结合了递归(如您从其他语言中所知道的)和回溯。但是有一个不错的出路。您可以考虑使用较小的程序,而不是原始程序。
为了更好地理解实际循环,这是称为failure-slice的最小程序片段,它是未终止的原因。其中还有一些额外的虚假之处:某些目标 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.