如果使用过Matlab或者Maple等软件,应该知道这类数学软件的符号计算引擎非常强大,可以进行数学公式的推导,比如可以对数学公式进行化简。当然,实现一个功能完备的化简引擎还是不容易的。这里用F# 实现一个简单的化简函数。
首先定义一个表达式数据类型:
typeExpr=|CstFoffloat|Varofstring|AddofExpr*Expr// +|SubofExpr*Expr// -|MulofExpr*Expr// *|DivofExpr*Expr// /
其次定义一个化简函数,它是化简规则的具体实现:
(*化简*) letrecsimplifye=matchewith|CstFf->CstFf|Varx->Varx|Add(CstFa, CstFb) ->CstF (a+b) |Add(CstF0., e2) ->simplifye2|Add(e1 , CstF0.) ->simplifye1|Add(e1 , e2) whene1=e2->simplify (Mul(CstF2., simplifye1)) |Add(Mul(CstFa, e1) , Mul(CstFb, e2)) whene1=e2->simplify (Mul(CstF (a+b), simplifye1)) |Add(e1,Sub(a,e2)) whene1=e2->simplifya|Add(Add(a, x1),Sub(b, x2)) whenx1=x2->simplify(Add(simplifya,simplifyb)) |Add(e1, e2) ->Add(simplifye1,simplifye2) |Mul(CstFa, CstFb) ->CstF (a*b) |Mul(CstF0., e2) ->CstF0.|Mul(e1 , CstF0.) ->CstF0.|Mul(CstF1., e2) ->simplifye2|Mul(e1 , CstF1.) ->simplifye1|Mul(e1, e2) ->Mul(simplifye1,simplifye2) |Sub(CstFa, CstFb) ->CstF (a-b) |Sub(Add(e1,e2),e3) whene1=e3->simplifye2|Sub(Add(e1,e2),e3) whene2=e3->simplifye1|Sub(e1, e2) whene1=e2->CstF0.|Sub(e1, e2) ->Sub(simplifye1,simplifye2) |Div(CstFa, CstFb) ->CstF (a/b) |Div(CstF0., e2) ->CstF0.|Div(e1, e2) whene1=e2->CstF1.|Div(e1, e2) ->Div(simplifye1,simplifye2) |_->failwith"unknown operation"
这个化简函数,返回一个是一个自定义DSL的表达式结构,如Sub(Var "a", Var "x") ,下面再定义一个可以化简和打印出字符串的函数:
letrecsimpe=letres=simplifyematchreswith|CstFf->stringf|Varx->x|Add(e1 , e2) ->"("+ (simpe1) +"+"+ (simpe2) +")"|Sub(e1 , e2) ->"("+ (simpe1) +"-"+ (simpe2) +")"|Mul(e1 , e2) ->"("+ (simpe1) +"*"+ (simpe2) +")"|Div(e1 , e2) ->"("+ (simpe1) +"/"+ (simpe2) +")"|_->failwith"unknown operation";;
最后,再定义一个打印DSL表达式的函数:
letrecprintExpre=matchewith|CstFf->stringf|Varx->x|Add(e1 , e2) ->"("+ (printExpre1) +"+"+ (printExpre2) +")"|Sub(e1 , e2) ->"("+ (printExpre1) +"-"+ (printExpre2) +")"|Mul(e1 , e2) ->"("+ (printExpre1) +"*"+ (printExpre2) +")"|Div(e1 , e2) ->"("+ (printExpre1) +"/"+ (printExpre2) +")"|_->failwith"unknown operation";;
至此,可以测试一下,如何化简数学表达式:
//( a + x ) + ( a - x )lete1=Add(Add(Var"a", Var"x"),Sub(Var"a", Var"x")) printExpre1+" => "+simpe1 ;;