% MPQ Meta Prolog with Questions...

:- op(1150,xfy,'if'),
   op(1100,xfy,'or'),
   op(1000,xfy,'and'),
   op(900,fy,'~').

:- dynamic answer/2, if/2.

% true succeeds.
demo(true) :- !.

% false fails.
demo(false) :- !,fail.

% conjunction
demo((P and Q)) :- !,demo(P),demo(Q).

% disjunction
demo((P or _)) :- demo(P).
demo((_ or Q)) :- !,demo(Q).

% negation 
demo(~P) :- demo(P),!,fail.
demo(~_) :- !.

% apply a rule
demo(P) :- (P if Q),demo(Q).

demo(P) :- askable(P),!,ask(P).

% fall through to prolog
demo(P) :- 
  builtin(P),
  !,
  call(P).

% succeeds if P is a builtin predicate (i.e., there
% is no meta rule for P).
builtin(P) :- 
  functor(P,Predicate,Arity),
  functor(P2,Predicate,Arity),
  \+((P2 if _)).

% fall through to prolog
demo(P) :- \+ ((P if _)), P.

%%% interaction component...

% if P has been asked about already, then remember the answer.
ask(P) :- answer(P,A),!,A=true.

% ask question and remember the result.
ask(P) :-
  ask1(P) -> assert(answer(P,true)) ; 
             (assert(answer(P,false)),fail).

%% ask1(P) will ask about proposition P.
  
% if we know a special way to ask, then use it.
ask1(P) :- toAsk(P,Method),!,Method.

% the default way to ask (i.e. if there is no toAsk method).
ask1(P) :- askYesNo("Is ~p true?",[P]).

%askYesNo(Q) asks a yes/no question Q.
askYesNo(Question,Args) :-
  format(Question,Args),
  write(" "),
  getYesNo.

%getYesNo gets a valid yes/no answer and succeeds if it
% is positive and fails if negative.
getYesNo :-
  read(Answer),
  checkYesNo(Answer).

%interprets a legal response or reasks.
checkYesNo(A) :-  postitiveAnswer(A),!.
checkYesNo(A) :-  negativeAnswer(A),!,fail.
checkYesNo(_) :-
  format("Please enter yes or no",[]),
  getYesNo.

postitiveAnswer(yes).
postitiveAnswer(y).
negativeAnswer(no).
negativeAnswer(n).

