【问题标题】:SWI-Prolog. Check correctness of mathematical expressionSWI-序言。检查数学表达式的正确性
【发布时间】:2012-04-03 02:15:33
【问题描述】:

我尝试使用 Prolog (SWI-Prolog) 检查学生数学表达式的正确性。因此,例如,如果要求学生添加三个变量 x、y 和 z,并且有一个规则,必须添加的前两个变量是:x 和 y(以任意顺序),最后一个必须添加的变量如果学生的答案是以下任何一个,那么我希望 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.

【问题讨论】:

    标签: prolog


    【解决方案1】:

    您应该尝试指定一个语法并为您的表达式编写一个解析器

    避免断言/撤回,这会使程序更加更难理解,而是尝试掌握 Prolog 的声明性模型。

    表达式是递归数据结构,使用具有已知优先级关联性运算符组成,括号根据需要更改指定的优先级。

    请参阅this 答案以获得解析器评估器,它接受来自文本的输入。在您的问题中,您显示来自 code 的表达式。然后,您正在使用 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 .
    

    编辑:我们可以提供一个我们想要的模板,让Prolog通过统一的方式处理细节:

    % 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.
    

    【讨论】:

    • 嗨,Chac,感谢您的建议。但是,在这种情况下,我想要一个代码来解决特定任务。所以在这种情况下,前两个可以相加的变量是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。谢谢
    • 嗯,保持声明性方法很重要:尝试编写最小代码,让您确定正确性。在您的情况下,提供 示例 可能很有用。查看编辑。
    • 嗨,查克。谢谢。是的,我会尝试在我的程序中使用更多的声明性方法。我以前的方法似乎仍然受到我作为 c# 程序员背景的很大影响。我喜欢解决的一个例子(会有很多)例如检查学生的数学表达式以将摄氏度转换为华氏度。学生可以写出我在之前评论中写过的任何表达式,但不能写出以下任何表达式:f = d*1.8+c, f=d*(1.8+c), f=c*(1.8+d ), 等等。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多