Recursion 如何在PROLOG中停止无限递归

Recursion 如何在PROLOG中停止无限递归,recursion,prolog,Recursion,Prolog,我有一个关于人们的知识库,根据一个数字,他们相互信任的程度,如果a信任B,那么B信任a的程度是相同的 trusts(josemari,lucia,4.0). trusts(raul,josemari,3.0). trusts(luis,felipe,2.0). trusts(manolo,felipe,2.5). trusts(pepe,vidal,1.0). trusts(pepe,luis,0.5). trusts(A,B,K):- trust

我有一个关于人们的知识库,根据一个数字,他们相互信任的程度,如果a信任B,那么B信任a的程度是相同的

  trusts(josemari,lucia,4.0).
  trusts(raul,josemari,3.0).
  trusts(luis,felipe,2.0).
  trusts(manolo,felipe,2.5).
  trusts(pepe,vidal,1.0).
  trusts(pepe,luis,0.5).

  trusts(A,B,K):-
         trusts(B,A,K).

这让我陷入了一个无限递归,那么,我怎么能打破这个递归呢?更改信任谓词不是选项,重写知识库添加对立面也不是选项。

您可以要求A和B绑定:

trusts(A,B,K) :- nonvar(A), nonvar(B), trusts(B,A,K)
但它只在某些情况下有效。也就是说,它永远不会被卡住,但你将无法使用它找到所有的信任关系

我认为更好的解决办法是将基本信任级别与高级信任关系分开。像

advanced_trust(A,B,K) :- trusts(A,B,K) ; trusts(B,A,K).

如果您使用的是SWI Prolog,则可以将谓词表化。只需添加一个
指令:

:- table trusts/3.

trusts(josemari,lucia,4.0).
trusts(raul,josemari,3.0).
trusts(luis,felipe,2.0).
trusts(manolo,felipe,2.5).
trusts(pepe,vidal,1.0).
trusts(pepe,luis,0.5).

trusts(A,B,K):-
     trusts(B,A,K).
现在它按预期工作:

?- trusts(josemari, X, Y).
X = lucia,
Y = 4.0 ;
X = raul,
Y = 3.0.

?- trusts(luis, X, Y).
X = pepe,
Y = 0.5 ;
X = felipe,
Y = 2.0.

?- trusts(X, luis, Y).
X = pepe,
Y = 0.5 ;
X = felipe,
Y = 2.0.

?- trusts(A, B, K), K >= 3.0.
A = josemari,
B = lucia,
K = 4.0 ;
A = josemari,
B = raul,
K = 3.0 ;
A = lucia,
B = josemari,
K = 4.0 ;
A = raul,
B = josemari,
K = 3.0 ;
false.
如果您没有SWI Prolog或其他具有tabling的实现,则需要使用不同的名称定义另一个规则:

trusts(josemari,lucia,4.0).
trusts(raul,josemari,3.0).
trusts(luis,felipe,2.0).
trusts(manolo,felipe,2.5).
trusts(pepe,vidal,1.0).
trusts(pepe,luis,0.5).

trusts_commutative(A, B, K):-
    trusts(A, B, K).
trusts_commutative(A, B, K):-
    trusts(B, A, K).
结果是一样的

?- trusts_commutative(X, luis, Y).
X = pepe,
Y = 0.5 ;
X = felipe,
Y = 2.0.

?- trusts_commutative(A, B, K), K >= 3.0.
A = josemari,
B = lucia,
K = 4.0 ;
A = raul,
B = josemari,
K = 3.0 ;
A = lucia,
B = josemari,
K = 4.0 ;
A = josemari,
B = raul,
K = 3.0 ;
false.

即使是
nonvar(A)
nonvar(B)
,它也会不断递归,因为
信任(A,B,K)
将调用
信任(B,A,K)
(仍然是变量),反之亦然)。@WillemVanOnsem当然,原始定义需要删除。如果它不能被移除,就没有什么可以做的。第一个解决方案是否适用于3个未绑定的变量,即它是否可以用于枚举所有信任关系?@YaroslavFyodorov您应该尝试一下。我自己检查过(必须先升级swipl,它升级了我一半的系统)。它适用于3个未绑定变量。基本上,它是这样做的:它用另一个名称定义原子谓词,在非原子谓词中,它在调用原始谓词的地方替换对这个新谓词的调用,从而防止无限递归。我把它拿回去,它更复杂