Courses/CS 332L/Expression evaluation
From CSWiki
[edit] Version 1
The following program will evaluate arithmetic expressions in + and *.
?- eval((3+4)*5, R). R = 35 ?- eval(3+4*5, R). R = 23 ?- eval((3+4)*x, R). R = 7*x
% eval(+Expression, ?Result) % If the input is of the form E1 + E2 eval(E1 + E2, Result) :- !, eval(E1, V1), eval(E2, V2), perform_op(+, V1, V2, Result). % If the input is of the form E1 * E2 eval(E1 * E2, Result) :- !, eval(E1, V1), eval(E2, V2), perform_op(*, V1, V2, Result). % Otherwise just return the expression unevaluated. eval(X, X). % To perform addition on V1 and V2, % make sure they are both numbers % and add them. perform_op(+, V1, V2, Result) :- number(V1), number(V2), !, Result is V1 + V2. % Same for multiplication perform_op(*, V1, V2, Result) :- number(V1), number(V2), !, Result is V1 * V2. % If the two arguments are not both numbers % put them together into an expression. % Use the univ operator: =.. perform_op(Op, V1, V2, Expr) :- !, Expr =.. [Op, V1, V2].
[edit] Version 2
This version looks up variables in a list of bindings.
?- eval(3+4*x, [x = 5], R). R = 23 ?- eval(z+4*x, [x = 5, z = 10], R). R = 30 ?- eval(z+a*x, [x = 5, z = 10, a = 3], R). R = 25 ?- eval(z+z*x, [x = 5, z = 10, a = 3], R). R = 60 ?- eval(z+w*(x+y), [x = 5, z = 10, y = 3], R). R = 10+w*8
% eval(+Expression, +Bindings, ?Result) eval(X, Bindings, V) :- member(X = V, Bindings), !. eval(X, _Bindings, X) :- atom(X), !. eval(E1 + E2, Bindings, Result) :- !, eval(E1, Bindings, V1), eval(E2, Bindings, V2), perform_op(+, V1, V2, Result). eval(E1 * E2, Bindings, Result) :- !, eval(E1, Bindings, V1), eval(E2, Bindings, V2), perform_op(*, V1, V2, Result). eval(X, _Bindings, X). perform_op(+, V1, V2, Result) :- number(V1), number(V2), !, Result is V1 + V2. perform_op(*, V1, V2, Result) :- number(V1), number(V2), !, Result is V1 * V2. perform_op(Op, V1, V2, Expr) :- !, Expr =.. [Op, V1, V2].
[edit] Version 3
Use univ (=..) in both directions.
% eval(+Expression, ?Result)
eval(X, Bindings, V) :-
member(X = V, Bindings),
!.
eval(X, _Bindings, X) :-
atom(X),
!.
eval(E1 + E2, Bindings, Result) :-
!,
eval(E1, Bindings, V1),
eval(E2, Bindings, V2),
perform_op(+, V1, V2, Result).
eval(E1 * E2, Bindings, Result) :-
!,
eval(E1, Bindings, V1),
eval(E2, Bindings, V2),
perform_op(*, V1, V2, Result).
eval(X, _Bindings, X).
% If the two arguments are both numbers
% put them together into an expression.
% Use the univ operator: =.. Then
% evaluate the expression using "is".
perform_op(Op, V1, V2, Result) :-
number(V1),
number(V2),
!,
Expr =.. [Op, V1, V2],
Result is Expr.
% If the two arguments are not both numbers
% put them together into an expression.
% Use the univ operator: =..
perform_op(Op, V1, V2, Expr) :-
!,
Expr =.. [Op, V1, V2].
[edit] Version 4
Use univ for eval also. Get subtraction, division, exponentiation, integer division, modulo and all the other 2-argument arithmetic functions described in section 4.26.3 of the online manual for "free."
?- eval(max(1, z/(w*(x-y)^y)), [w = 1, x = 5, z = 10, y = 3], R). R = 1.25
% eval(+Expression, +Bindings, ?Result)
eval(X, Bindings, V) :-
member(X = V, Bindings),
!.
eval(X, _Bindings, X) :-
atomic(X),
!.
eval(Expr, Bindings, Result) :-
% current_arithmetic_function/1 succeeds if Expr
% unifies with a defined arithmetic function.
current_arithmetic_function(Expr),
Expr =.. [Op, E1, E2],
!,
eval(E1, Bindings, V1),
eval(E2, Bindings, V2),
perform_op(Op, V1, V2, Result).
eval(Expr, _Bindings, _Result) :-
Expr =.. [Op, _E1, _E2],
!,
write('Not a defined binary arithmetic function: '),
writeln(Op),
fail.
eval(X, _Bindings, X).
perform_op(Op, V1, V2, Result) :-
number(V1),
number(V2),
!,
Expr =.. [Op, V1, V2],
Result is Expr.
perform_op(Op, V1, V2, Expr) :-
!,
Expr =.. [Op, V1, V2].

