% Decision procedure for purely linear logic
% (multiplicative additiive linear logic)
% on the syntax of ordered logic

% A,B ::= P
%       | A \ B | B / A | A & B | t
%       | A * B | 1 | A + B | 0
%
% O ::= [A1,...,An]

% All operators are non-associative to avoid errors
:- op(850, xfx, \).
:- op(850, xfx, /).
:- op(850, xfx, *).
:- op(850, xfx, &).
:- op(850, xfx, +).

merge([],     [],     []).
merge([X|Xs], Ys, [X|Zs]) :- merge(Xs, Ys, Zs).
merge(Xs, [Y|Ys], [Y|Zs]) :- merge(Xs, Ys, Zs).

right(O, A \ B) :- right([A|O], B).
right(O, B / A) :- right([A|O], B).
right(O, A & B) :- right(O, A), right(O, B).
right(_, t)     :- true.
right(O, A * B) :- merge(O1, O2, O), right(O1, A), right(O2, B).
right(O, 1)     :- O = [].
right(O, A + _) :- right(O, A).
right(O, _ + B) :- right(O, B).
% right(O, 0)     :- fail.
right(O, C) :- append(OL, [A|OR], O), append(OL, OR, O1), left(O1, A, C).

left(O, A \ B, C) :- merge(O1, O2, O), right(O2, A), right([B|O1], C).
left(O, B / A, C) :- merge(O1, O2, O), right(O1, A), right([B|O2], C).
left(O, A & _, C) :- right([A|O], C).
left(O, _ & B, C) :- right([B|O], C).
% left(O, t, C)   :- fail.
left(O, A * B, C) :- right([A|[B|O]], C).
left(O, 1,     C) :- right(O, C).
left(O, A + B, C) :- right([A|O], C), right([B|O], C).
left(_ , 0,    _) :- true.
left([], C,    C).

prove(A) :- format(" ==> ~p~n", [A]), fail.
prove(A) :- right([], A).

equiv(A,B) :- format("~p <=> ~p~n", [A,B]), fail.
equiv(A,B) :- right([A], B), right([B], A).
