2012-04-03 83 views
1

我尝试使用Prolog(SWI-Prolog)检查学生数学表达式的正确性。因此,例如,如果要求学生添加三个变量x,y和z,并且有一条规则,即必须添加的前两个变量是:x和y(以任意顺序),并且必须添加最后一个变量被添加为z然后我想到的是序言可以给我真正的价值,如果学生的答案是任何一种:SWI-Prolog。检查数学表达式的正确性

X + Y + Z

(X + Y)+ Z

Z +(X + Y)

Z + X + Y

Y + X + Z

和许多其他的可能性。

我用下面的规则此检查:

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. 

回答

1

你应该尝试指定语法谱写解析器为你的表情。

避免断言/收缩,使得该软件更难于理解,并试图而是掌握的Prolog的声明模型。

表达式是递归数据结构,使用运营与已知优先关联组成,和括号其中需要改变指定的优先级。

this答案解析器评估,从文本接受输入。在你的问题中,你会显示来自的代码。然后,您使用的Prolog”解析器做肮脏的工作,并且可以简单地表达对所得到的语法树您的要求:

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 . 

编辑:我们可以提供我们所需要的模板,让序言通过统一的方式工作的细节:

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

等等......

测试:

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

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

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

您好,谢谢您的建议。但是,在这种情况下,我想有一个代码来解决特定的任务。所以在这种情况下,可以添加的前两个变量是x和y,然后可以将这个添加的结果添加到z中。所以在这种情况下正确的表达式就是:x + y + z,y + x + z,(x + y)+ z,(y + x)+ z,z +(x + y),z +(y + x )。举一个真实的例子来解决这个任务:从摄氏度计算华氏度(d中的商店32)。那么该解决方案只能有:f = c * 1.8 + d,f = 1.8 * c + d,f = d + c * 1.8,f = d + 1.8 * c,以及一些带括号的变体,例如:f = (C * 1.8)+ d。谢谢 – 2012-04-06 02:20:02

+0

好吧,保持* declarative *方法很重要:试图编写* minimal *代码,让您确定正确性。在你的情况下,可以提供*例子*。查看编辑。 – CapelliC 2012-04-06 06:02:46

+0

嗨chac。谢谢。是的,我会尝试在我的程序中做更多的声明性方法。作为一名c#程序员,我以前的方法似乎仍然从我的背景中受到很大影响。例如,我喜欢解决的一个案例(其中会有很多),例如检查学生的数学表达式,将摄氏温度转换为华氏温度。学生可以写出我在前面评论中写出的任何表达方式,但不是任何这些表达式:f = d * 1.8 + c,f = d *(1.8 + c),f = c *(1.8 + d ), 等等。谢谢 – 2012-04-06 06:12:52