% Programs D ::= P | imp(G,D) [ | forall(X,D) ]
% Goals    G ::= P | and(G1,G2) | true [ | 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,P) succeeds if Gamma, [D] --> P
solve(true).
solve(and(G1,G2)) :- solve(G1), solve(G2).
solve(P) :- atm(P), prog(D), focus(D, P).

% focus(Q,P) :- atm(Q), Q = P.   % unsound unification
focus(Q,P) :- atm(Q), unify_with_occurs_check(Q,P).
focus(imp(G,D),P) :- focus(D,P), solve(G).
