سؤال
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.
المحلول 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]).
نصائح أخرى
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:
- Report a bug to SWI developers
- Replace clauses in
birds.nkb
by something likemyclause
and refer tomyclause
in the implementation of the shell. - 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).