%% 15-317 S'23
%% Metainterpreter for (pure) Prolog
%% Live-coded, Thu Mar 30, 2023

mem(Dcopy, [D | Gamma]) :- copy_term(D, Dcopy).
mem(Dcopy, [_ | Gamma]) :- mem(Dcopy, Gamma).

unify(P,Q) :- unify_with_occurs_check(P,Q).
% unify(P,P).  % Prolog, but logically unsound

choose(Gamma, atom(P)) :-
    mem(D, Gamma),
    focusL(Gamma, D, atom(P)).

focusL(Gamma, atom(Q), atom(P)) :- unify(Q,P).
focusL(Gamma, imp(G,atom(Q)), atom(P)) :-
    unify(Q,P),
    focusR(Gamma, G).

focusR(Gamma, and(G1,G2)) :-
    focusR(Gamma, G1),
    focusR(Gamma, G2).
focusR(Gamma, atom(P)) :-
    choose(Gamma, atom(P)).

%% examples

ex1([atom(p), imp(atom(p),atom(q)), atom(q),
     imp(atom(q), atom(r))]).
query1 :- ex1(Gamma), choose(Gamma, atom(r)).

ex2([imp(atom(p),atom(p)), atom(p)]).
query2 :- ex2(Gamma), choose(Gamma, atom(p)).

ex3([atom(plus(0, Y, Y)),
     imp(atom(plus(X, Y, Z)), atom(plus(s(X), Y, s(Z))))]).

query3(Z) :- ex3(Gamma),
             choose(Gamma, atom(plus(s(0), s(s(0)), Z))).
query4(X,Y) :- ex3(Gamma),
               choose(Gamma, atom(plus(X, Y, s(s(s(s(0))))))).
