% Programs D ::= P | imp(G,D) | and(D1,D2) [ | forall(X,D) ]
% Goals    G ::= P | and(G1,G2) | true | or(G1,G2) | false [ | exists(X,G) ]

atm(inc(_,_)).

prog(inc(e,b1(e))).
prog(inc(b0(M),b1(M))).
prog(imp(inc(M,N),inc(b1(M),b0(N)))).

% solve(G) succeeds if Gamma --> G
% focus(D,Q) succeeds if Gamma, [D] --> Q

% tracing encountered goals
% solve(G) :- display(G), nl, fail.

solve(true).
solve(and(G1,G2)) :- solve(G1), solve(G2).
solve(or(G1,G2)) :- solve(G1).
solve(or(G1,G2)) :- solve(G2).
% no clause for solve(false)
solve(P) :- atm(P), prog(D), focus(D,P).

focus(imp(G,D),P) :- focus(D,P), solve(G).
focus(and(D1,D2),P) :- focus(D1, P).
focus(and(D1,D2),P) :- focus(D2, P).
focus(Q,P) :- atm(Q), unify_with_occurs_check(Q,P).
