Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
608 views
in Technique[技术] by (71.8m points)

refactoring - DRY arithmetic expression evaluation in Prolog

I wanted to write evaluating predicate in Prolog for arithmetics and I found this:

eval(A+B,CV):-eval(A,AV),eval(B,BV),CV is AV+BV.
eval(A-B,CV):-eval(A,AV),eval(B,BV),CV is AV-BV.
eval(A*B,CV):-eval(A,AV),eval(B,BV),CV is AV*BV.
eval(Num,Num):-number(Num).

Which is great but not very DRY.

I've also found this:

:- op(100,fy,neg), op(200,yfx,and), op(300,yfx,or).

positive(Formula) :-
    atom(Formula).

positive(Formula) :-
    Formula =.. [_,Left,Right],
    positive(Left),
    positive(Right).

?- positive((p or q) and (q or r)).
Yes
?- positive(p and (neg q or r)).
No

Operator is here matched with _ and arguments are matched with Left and Right.

So I came up with this:

eval(Formula, Value) :-
    Formula =.. [Op, L, R], Value is Op(L,R).

It would be DRY as hell if only it worked but it gives Syntax error: Operator expected instead.

Is there a way in Prolog to apply operator to arguments in such a case?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your almost DRY solution does not work for several reasons:

  • Formula =.. [Op, L, R] refers to binary operators only. You certainly want to refer to numbers too.

  • The arguments L and R are not considered at all.

  • Op(L,R) is not valid Prolog syntax.

on the plus side, your attempt produces a clean instantiation error for a variable, whereas positive/1 would fail and eval/2 loops which is at least better than failing.

Since your operators are practically identical to those used by (is)/2 you might want to check first and only then reuse (is)/2.

eval2(E, R) :-
   isexpr(E),
   R is E.

isexpr(BinOp) :-
   BinOp =.. [F,L,R],
   admissibleop(F),
   isexpr(L),
   isexpr(R).
isexpr(N) :-
   number(N).

admissibleop(*).
admissibleop(+).
% admissibleop(/).
admissibleop(-).

Note that number/1 fails for a variable - which leads to many erroneous programs. A safe alternative would be

t_number(N) :-
   functor(N,_,0),
   number(N).

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...