1

I try to check the correctness of student mathematical expression using Prolog (SWI-Prolog). So, for example if the student were asked to add three variable x, y, and z, and there's a rule that the first two variable that must be added are: x and y (in any order), and the last variable that must be added is z then I expect that prolog can give me true value if the student's answer is any of these:

x+y+z

(x+y)+ z

z+(x+y)

z+x+y

y+x+z

and many other possibilities.

I use the following rule for this checking:

addData :-
    assert(variable(v1)),
    assert(variable(v2)),
    assert(variable(v3)),
    assert(varName(v1,x)),
    assert(varName(v2,y)),
    assert(varName(v3,z)),
    assert(varExpr(v1,x)),
    assert(varExpr(v2,y)),
    assert(varExpr(v3,z)).


add(A,B,R) :- R = A + B.

removeAll :- retractall(variable(X)),
    retractall(varName(X,_)),
    retractall(varExpr(X,_)).


checkExpr :-
         % The first two variable must be x and y, in any combination
         (   (varExpr(v1,AExpr), varExpr(v2,BExpr));
             (varExpr(v2,AExpr), varExpr(v1,BExpr))
         ),
         add(AExpr, BExpr, R1),

         % store the expression result as another variable, say v4
         retractall(variable(v4)),
         retractall(varName(v4, _)),
         retractall(varExpr(v4, _)),

         assert(variable(v4)),
         assert(varName(v4, result)),
         assert(varExpr(v4, R1)),

         % add the result from prev addition with Z (in any combination)
         (   (varExpr(v3,CExpr), varExpr(v4,DExpr));
             (varExpr(v4,CExpr), varExpr(v3,DExpr))
         ),

         add(CExpr, DExpr, R2),

         R2 =  z + x + y.               % will give me false
        % R2 =  z + (x + y).            % will give me true
                                        % Expected: both should give me true


checkCorrect :- removeAll,
            addData,
            checkExpr.
false
  • 10,264
  • 13
  • 101
  • 209
Budi Hartanto
  • 337
  • 3
  • 14

1 Answers1

1

You should try to specify a grammar and write a parser for your expressions.

Avoid assert/retract, that make the program much more difficult to understand, and attempt instead to master the declarative model of Prolog.

Expressions are recursive data structures, using operators with known precedence and associativity to compose, and parenthesis to change specified precedence where required.

See this answer for a parser and evaluator, that accepts input from text. In your question you show expressions from code. Then you are using Prolog' parser to do the dirty work, and can simply express your requirements on the resulting syntax tree:

expression(A + B) :-
  expression(A),
  expression(B).
expression(A * B) :-
  expression(A),
  expression(B).

expression(V) :-
  memberchk(V, [x,y,z]).

?- expression(x+y+(x+z*y)).
true .

edit: we can provide a template of what we want and let Prolog work out the details by means of unification:

% enumerate acceptable expressions
checkExpr(E) :-
  member(E, [F = A + D, F = D + A]),
  F = f,
  A = c * N,
  N = 1.8,
  D = d.

And so on...

Test:

?- checkExpr(f=(c*1.8)+d).
true.

?- checkExpr(f=(c*1.8)+e).
false.

?- checkExpr(f=d+c*1.8).
true.
Community
  • 1
  • 1
CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • Hi Chac, thanks for the suggestion. However, in this case I would like to have a code to solve specific task. So in this case, the first two variable that can be added are x and y, then the result of this addition can be added to z. So the correct expression in this case is just: x+y+z, y+x+z, (x+y)+z, (y+x)+z, z+(x+y), z+(y+x). A real case for example is to solve this task: calculate degree fahrenheit from degree celcius (store 32 in d). Then the solution could only: f=c*1.8+d, f=1.8*c+d, f=d+c*1.8, f=d+1.8*c, and some variants with parenthesis on it such as: f=(c*1.8)+d. Thanks – Budi Hartanto Apr 06 '12 at 02:20
  • Well, it's important to keep a *declarative* approach: attempt to write the *minimal* code that let you determine the correctness. In your case, could be useful to provide *examples*. See the edit. – CapelliC Apr 06 '12 at 06:02
  • Hi chac. Thanks. Yes, I'll try to do more declarative approach in my program. My previous approach seems still get influence a lot from my background as a c# programmer. One example of case that I like to solve (there will be lots of them) is for example to check student's math expression for converting celsius to fahrenheit. The students can write any of those expression that I wrote on previous comment, but not for example any of these expressions: f = d*1.8+c, f=d*(1.8+c), f=c*(1.8+d), and so on. Thanks – Budi Hartanto Apr 06 '12 at 06:12