在Prolog metainterpreter中循环

时间:2015-12-11 07:16:06

标签: prolog

我在Prolog中为自我教育写了一个简单的元解释器。基本上我想继承给定解决方案的“概率”。为此,我只声明我的条款正确的概率。我希望如果这有效,我会用更好的基础扩展它,但是现在我只对解决当前问题感兴趣,这就是我的metainterpreter循环:

代码:

fuzzy_prove(true, 1.0) :- !.
fuzzy_prove(probability(P), P) :- !.
fuzzy_prove((A,B), Prob) :-
    fuzzy_prove(A, P1),
    fuzzy_prove(B, P2),
    Prob is P1 * P2.
fuzzy_prove(A, P) :-
    clause(A, B), fuzzy_prove(B, P).

father(dave, jean).
father(dave, don) :- probability(0.5).
father(don, claudia).
father(don, jimmy) :- probability(0.5).
father(jean, davey).

grandfather(Grandpop, Babs) :-
    father(Grandpop, Dad),
    father(Dad, Babs).

我的查询起初似乎起作用了:

?- fuzzy_prove(grandfather(X, Z), Prob).
X = dave,
Z = davey,
Prob = 1.0 ;
X = dave,
Z = claudia,
Prob = 0.5 ;
X = dave,
Z = jimmy,
Prob = 0.25 ;

当我要求下一个解决方案时,我会疯狂地循环。如果我打断它,它看起来像这样:

continue (trace mode)
   Call: (3,973,299) fuzzy_prove(call((father(_G3, _G28), father(_G28, _G4))), _G5) ? 
^  Call: (3,973,300) clause(call((father(_G3, _G28), father(_G28, _G4))), _G2044) ? 
^  Exit: (3,973,300) clause(call((father(_G3, _G28), father(_G28, _G4))), call((father(_G3, _G28), father(_G28, _G4)))) ? 
   Call: (3,973,300) fuzzy_prove(call((father(_G3, _G28), father(_G28, _G4))), _G5) ? 
^  Call: (3,973,301) clause(call((father(_G3, _G28), father(_G28, _G4))), _G2051) ? 
^  Exit: (3,973,301) clause(call((father(_G3, _G28), father(_G28, _G4))), call((father(_G3, _G28), father(_G28, _G4)))) ? 
   Call: (3,973,301) fuzzy_prove(call((father(_G3, _G28), father(_G28, _G4))), _G5) ? 
^  Call: (3,973,302) clause(call((father(_G3, _G28), father(_G28, _G4))), _G2058) ? 
^  Exit: (3,973,302) clause(call((father(_G3, _G28), father(_G28, _G4))), call((father(_G3, _G28), father(_G28, _G4)))) ? 
   Call: (3,973,302) fuzzy_prove(call((father(_G3, _G28), father(_G28, _G4))), _G5) ? 
^  Call: (3,973,303) clause(call((father(_G3, _G28), father(_G28, _G4))), _G2065) ? 
^  Exit: (3,973,303) clause(call((father(_G3, _G28), father(_G28, _G4))), call((father(_G3, _G28), father(_G28, _G4)))) ? 
   Call: (3,973,303) fuzzy_prove(call((father(_G3, _G28), father(_G28, _G4))), _G5) ? 
^  Call: (3,973,304) clause(call((father(_G3, _G28), father(_G28, _G4))), _G2072) ? 
^  Exit: (3,973,304) clause(call((father(_G3, _G28), father(_G28, _G4))), call((father(_G3, _G28), father(_G28, _G4)))) ? 

我确信我做的事情显然很愚蠢,但我很难看到它是什么。

2 个答案:

答案 0 :(得分:3)

你的子句与(,)仿函数匹配两次:fuzzy_prove的第3和第4个子句,当它与第4个子句匹配时,它最终将无限循环,因为子句本身是一个并且不能简化。

此查询将演示正在发生的事情:

clause(grandfather(A,B), C0), clause(C0, C1), clause(C1, C2).

在我的翻译中,至少C1 = C2,我们有一个无限循环。

在递归之前,您至少需要检查子句体的仿函数是否(,)。我怀疑会有其他像这样的角落情况,所以事实上最好找出如何正确处理调用仿函数。

答案 1 :(得分:2)

您遇到的问题特定于SWI。只有SWI才能成功 目标clause((A,B),R)。 ISO要求发出permission_error(access,private_procedure,Culprit)和B,IF,IV,GNU,SICStus,XSB和YAP都会产生此错误。请注意实际原因:private_procedure,对于内置插件和控件构造都是私有的,即无法通过clause/2访问它们。

您的代码还有许多其他问题。

目标fuzzy_prove(true,0.0)产生了非常错误,而不是无声地失败。简而言之,你的代码缺乏坚定性。

另一个问题是fuzzy_prove(G, P),它可能应该提供相应的实例化错误,而不是G = true

fuzzy_prove(probability(1.0),0.0)取决于是否存在相应的谓词,可能这不是预期的。如果没有,SWI会警告你probability/1不存在。