Reputation: 22803
I'm writing a trivial metainterpreter in Prolog for self-education. Basically I want to carry along the "probability" of a given solution. To do this I just declare the probability of my clause being correct. I expect if this works I will extend it with a better foundation but for now I'm just interested in solving the immediate problem, which is that my metainterpreter loops:
Code:
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).
My queries seem at first to work:
?- 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 ;
When I ask for the next solution, I get crazy looping. If I interrupt it, it looks like this:
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)))) ?
I'm sure I'm doing something obviously stupid but I'm having trouble seeing what it is.
Upvotes: 4
Views: 124
Reputation: 10142
The problem you encountered is specific to SWI. Only SWI succeeds for
a goal clause((A,B),R)
. ISO demands to issue a permission_error(access,private_procedure,Culprit)
and B, IF, IV, GNU, SICStus, XSB, and YAP all produce this error. Note the actual reason: private_procedure
, for built-ins and control constructs are all private, i.e., they cannot be accessed via clause/2
.
There are many other issues with your code.
The goal fuzzy_prove(true,0.0)
produces that very error instead of failing silently. Brief, your code lacks steadfastness.
Another issue is fuzzy_prove(G, P)
which probably should rather give a corresponding instantiation error instead of G = true
.
fuzzy_prove(probability(1.0),0.0)
depends on the presence of a corresponding predicate, probably this is not intended. And if not, SWI will warn you about the nonexistence of probability/1
.
Upvotes: 2
Reputation: 28099
Your clause with (,) functors matches twice: both the 3rd and 4th clauses of fuzzy_prove, when it matches the 4th clause it will eventually loop infinitely because the clause body is itself an and and cannot be simplified.
This query will demonstrate what is happening:
clause(grandfather(A,B), C0), clause(C0, C1), clause(C1, C2).
On my interpreter at least C1 = C2, and we have an infinite loop.
You need at least to check that the functor of your clause body is not (,) before recursing. I suspect there will be other corner cases like this so it may in fact be better to work out how to handle the call functor correctly.
Upvotes: 3