用SML求和两个分数

时间:2016-11-15 15:42:21

标签: pattern-matching sml

我有一个已定义的数据类型

datatype expression = Constant of int
                    | Variable of string
                    | Operator of string * expression
                    | Pair of expression list
                    | List of expression list

我得到了两个有以下形式的分数:

Operator("/", Pair [Constant x, Constant y])

Operator("/", Pair [Variable x, Constant y])

我需要将这两个分数相加并返回一个新的表达式,它将两个分母中最小公倍数作为分母。
我设法让它工作,但我的代码似乎不必要地复杂和复杂。有没有办法写这个更短? 到目前为止我做了什么:

fun add (a,b) = 
    case (a,b) of 
            (Operator("/", Pair [Constant x1, Constant y1]), 
            Operator("/", Pair [Constant x2, Constant y2])) 
             => Operator("/", Pair [Constant ((x1*((lcm(y1,y2) div y1)))+(x2*(lcm(y1,y2) div y2))), Constant (lcm(y1,y2))])
            | (Operator("/", Pair [Variable x1, Constant y1]),
                Operator("/", Pair [Constant x2, Constant y2 ])) 
                => Operator("/", Pair[
                        Operator("+", Pair[ 
                            Operator("*", Pair[Variable x1, Constant (lcm(y1,y2) div y1)]),
                            Constant (x2* (lcm(y1,y2) div y2)) ]),
                        Constant (lcm(y1,y2))])

            | (Operator("/", Pair [Constant x1, Constant y1]),
                Operator("/", Pair [Variable x2, Constant y2 ])) 
                => Operator("/", Pair[
                        Operator("+", Pair[ 
                            Operator("*", Pair[Variable x2, Constant (lcm(y1,y2) div y2)]),
                            Constant (x1* (lcm(y1,y2) div y2)) ]),
                        Constant (lcm(y1,y2))])
            | (Operator("/", Pair [Variable x1, Constant y1]),
                Operator("/", Pair [Variable x2, Constant y2 ])) 
                => Operator("/", Pair[
                        Operator("+", Pair[
                            Operator("*", Pair[Variable x1, Constant (lcm(y1,y2) div y1)]), 
                            Operator("*", Pair[Variable x2, Constant (lcm(y1,y2) div y2)])]),
                        Constant (lcm(y1,y2))])

1 个答案:

答案 0 :(得分:4)

  

有没有办法把它写得更短?

是。瞄准最简单的模式。例如。如果要构建抽象语法树,

fun add (e1, e2) = Operator ("+", Pair [e1, e2])

如果您正在评估语法树,

fun eval env exp =
    case exp of
         Constant i => i
       | Variable x => lookup x env
       | Operator (oper, exps) => evalOp env oper (map (eval env) exps)
       | ... => ???

and evalOp env "+" is = foldl op+ 0 is
  | evalOp env "-" is = foldl op- 0 is
  | ...

特别是:您可能想重新考虑对和列表可以评估的有意义的标量值,以及是否应该将对和列表限制为语法树的某些部分。

通常:每当您的模式更深层匹配一个级别时,匹配个案的数量乘以构造函数的数量。一个或两个匹配级别通常就足够了。如果没有,编写执行更深匹配的辅助函数几乎总是理所当然的选择。