避免Prolog中的无限循环

避免Prolog中的无限循环,prolog,infinite-loop,Prolog,Infinite Loop,我在知识库中有以下事实: line(a,b). -- denotes the line determined by point a and b line(c,d). -- denotes the line determined by point c and d lineEqual(line(a,b),line(c,d)) -- denotes the length of two lines are equal 我想要另一条规则,可以围绕lineEqual/2的两个参数进行交换: lineEqu

我在知识库中有以下事实:

line(a,b). -- denotes the line determined by point a and b
line(c,d). -- denotes the line determined by point c and d
lineEqual(line(a,b),line(c,d)) -- denotes the length of two lines are equal
我想要另一条规则,可以围绕lineEqual/2的两个参数进行交换:

lineEqual(line(C, D), line(A, B)):-
    lineEqual(line(A,B),line(C,D)). 
不幸的是,该规则将在Prolog中创建一个无限循环。还有别的想法吗

谢谢你的更新。不确定我是否理解你的上一条规则:

transitiveSymmetricRelPath(L1, L2, IntermediateNodes) :- symmetricRel(L1, L3),
                 \+member(L3, IntermediateNodes),
                 transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]). 
我可以想象每次它试图剥离头部节点时,如果它恰好与L1和L3链接,对吗?因此,如果我们最终得到一个空列表,那么我们可以使用以下规则:

transitiveSymmetricRel(L1, L2) :- transitiveSymmetricRelPath(L1, L2, []). 
但我没有真正了解的是,从哪里可以得到transitiveSymmetricRelPath/3中间节点的非空列表。实际上,我已经用给定的事实rel(a,b)尝试了您的代码。rel(a,c)。它不返回transitivesymmetrel(b,c),也不返回transitivesymmetrel(c,b)。你能看一下吗

非常感谢

编辑: 我通过修改您的规则使其正常工作,如:

transitiveSymmetricRelPath(L2, L3, IntermediateNodes) :- symmetricRel(L1, L3),
     \+member(L3, IntermediateNodes),
     transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]). 

无论如何感谢您的建议。

您应该避免在单个名称下引入语句(如第一个示例中的
line
lineEqual
)和代码(如第二个示例中的
lineEqual
)。相反,请使用不同的名称保存数据库事实。然后,您可以定义,例如:

areLinesEqual(L1, L2) :- linesEqual(L1, L2).
areLinesEqual(L1, L2) :- linesEqual(L2, L1).
通常,如果您有一个关系
rel
,并且您想要构建一个对称传递闭包,那么您应该一次引入一个概念。例如:

symmetricRel(L1, L2) :- rel(L1, L2).
symmetricRel(L1, L2) :- rel(L2, L1).

transitiveSymmetricRel(L1, L2) :-
    transitiveSymmetricRelPath(L1, L2, []).

transitiveSymmetricRelPath(L1, L2, _) :-
    symmetricRel(L1, L2).

transitiveSymmetricRelPath(L1, L2, IntermediateNodes) :-
    symmetricRel(L1, L3),
    \+ member(L3, IntermediateNodes),
    transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]).
(注意,这里我们必须基本上在无向图中找到一条路径,并且必须注意避免循环)。在您的情况下,也可能需要考虑<代码>行(a,b)< /代码>和<代码>行(b,a)< /代码>。为此,您应该再次引入另一个间接层次:

% to check two lines for identity
same(line(A, B), line(A, B)).
same(line(A, B), line(B, A)).

linesEqual2(L1, L2) :-
    same(L1, LI1),
    same(L2, LI2),
    (linesEqual(LI1, LI2); linesEqual(LI2, LI1)).
…并在对称关系的定义中使用
linesEqual2
而不是
linesEqual

现在最困难的部分是一个命名方案,这样你就不会混淆所有这些谓词


你也可以用另一种方式。假设您寻求对称关系的传递闭包,它基本上是将所有节点集(此处为线)划分为可分离子集。此洞察将帮助您编写比上述更高效的代码……但这已经超出了此问题的范围。

感谢您的回答。传递关系呢?根据你的建议,我可能需要写8条规则:areLinesEqual(L1,L3):-linesEqual(L2,L1),linesEqual(L2,L3)。areLinesEqual(L1,L3):-linesEqual(L1,L2),linesEqual(L2,L3)。areLinesEqual(L1,L3):-linesEqual(L2,L1),linesEqual(L3,L2)。areLinesEqual(L1,L3):-linesEqual(L1,L2),linesEqual(L3,L2)。还有4条交换L1和L3的规则,对吗?可能不是一个好办法。谢谢你的更新,我已经根据你的回答编辑了这个问题。