
% evaluate prefix expressions on binary operators
%    where the expressions are in list form
% e.g.  prefix([ +, -, 3, 1, 5 ], Answer)
%    computes (+ (- 3 1) 5),
%    i.e. Answer = (3 - 1) + 5

% simple cases, numbers in front
prefix([N], [N]) :- number(N).
prefix([N1,N2|R], [N1,N2|R]) :- number(N1), number(N2).

% operator in front, followed by the two values it will be applied to
prefix([Op,N1,N2|Rest],[V|Rest]) :- op(Op), applyOp(Op,N1,N2,V).

% operators in first and second positions,
%    evaluate the later op before applying first
prefix([Op1,Op2|Rest],R) :- op(Op1), op(Op2),
   prefix([Op2|Rest], Tmp), prefix([Op1|Tmp], R).

% operators in first and third positions,
%    evaluate the later op before applying first
prefix([Op,N1|Rest],[V|R]) :- op(Op), number(N1), prefix(Rest, [N2|R]), applyOp(Op,N1,N2,V).

% identify valid ops
op(+).  op(-).  op(*).  op(/).

% apply valid binary ops
applyOp(+, X, Y, R) :- number(X), number(Y), Z is X + Y, Z = R.
applyOp(-, X, Y, R) :- number(X), number(Y), Z is X - Y, Z = R.
applyOp(/, X, Y, R) :- number(X), number(Y), Z is X / Y, Z = R.
applyOp(*, X, Y, R) :- number(X), number(Y), Z is X * Y, Z = R.

%
