Question

Recently I tried the book "Building Expert Systems in Prolog" which is freely available at http://www.amzi.com/ExpertSystemsInProlog.

There is a code called native shell at the appendix along with a bird identification database. The problem is that after consulting with the shell and running:

main.

load.

solve.

It asks "nostrils:external_tubular?"

If you answer no, then an stack overflow occurs. The problem is probably at the section blow:

prove(true,_) :- !.
prove((Goal,Rest),Hist) :-
    prov(Goal,[Goal|Hist]),
    prove(Rest,Hist).
prove(Goal,Hist) :-
    prov(Goal,[Goal|Hist]).

prov(true,_) :- !.
prov(menuask(X,Y,Z),Hist) :- menuask(X,Y,Z,Hist), !.
prov(ask(X,Y),Hist) :- ask(X,Y,Hist), !.
prov(Goal,Hist) :-
    clause(Goal,Body),
    prove(Body,Hist).

Can somebody please please help me? Any help is highly appreciated.

Full code of the shell: http://www.amzi.com/ExpertSystemsInProlog/code/native/native.pro

Full code for database: http://www.amzi.com/ExpertSystemsInProlog/code/native/birds.nkb

I'm using swi prolog.

Was it helpful?

Solution 2

I found the problem to be here:

prove((Goal,Rest),Hist) :-
    prov(Goal,[Goal|Hist]),
    prove(Rest,Hist).
prove(Goal,Hist) :-
    prov(Goal,[Goal|Hist]).

Since swi-prolog allows the head ((x,y,z), [h]) to match the second prove predicate, somehow in the inference process the prove(Goal,Hist) is triggered which will cause the infinite loop to occur. It took me 8 hours to analyze the trace.

Therefore to fix the issue, we need a cut to be placed in the beginning of prove((Goal,Rest),Hist). The code should look like this:

prove((Goal,Rest),Hist) :-
    !,
    prov(Goal,[Goal|Hist]),
    prove(Rest,Hist).
prove(Goal,Hist) :-
    prov(Goal,[Goal|Hist]).

OTHER TIPS

The problem indeed manifests itself through

prove(Goal,Hist) :-
    prov(Goal,[Goal|Hist]).

prov(Goal,Hist) :-
    clause(Goal,Body),
    prove(Body,Hist).

clause(:Head, ?Body) should be true if Head can be unified with a clause head and Body with the corresponding clause body. Unfortunately, for any program SWI-Prolog believes clause(call(X), call(X)) to be true. This means that clause(call(nostrils(external_tubular)), X) succeeds and prove is being called, which in its turn calls prov with ever-growing second argument.

Since clause/2 is a static predicate, its contents cannot be modified with retractall or abolish. Possible solutions are:

  1. Report a bug to SWI developers
  2. Replace clauses in birds.nkb by something like myclause and refer to myclause in the implementation of the shell.
  3. Look at some other Prolog dialects...

You can also fix it by adding the predicate prov((_,_),_) :- !, fail. right above the section:

prov(true,_) :- !.
prov(menuask(X,Y,Z),Hist) :- menuask(X,Y,Z,Hist), !.
prov(ask(X,Y),Hist) :- ask(X,Y,Hist), !.
prov(Goal,Hist) :-
    clause(Goal,Body),
    prove(Body,Hist).
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top