let rec simplify : aexpr -> aexpr = function | CstI i -> CstI i | Var v -> Var v | Add(e1,e2) -> match simplify2 e1 e2 with // Common addition of integers. | (CstI i1, CstI i2) -> CstI (i1 + i2) // 0 + e = e + 0 = e | (CstI 0, e) | (e, CstI 0) -> e // i1 + (i2 + e) = i3 + e where i3 = i1 + i2 | (CstI i1, Add (CstI i2, e)) -> Add (CstI (i1 + i2), e) // i1 + (i2 - e) = i3 - e where i3 = i1 + i2 | (CstI i1, Sub (CstI i2, e)) -> Sub (CstI (i1 + i2), e) // e + e = 2 * e | (f1, f2) when f1 = f2 -> Mul (CstI 2, f1) // i * e + e = e + i * e = (i + 1) * e | (Mul (CstI i, f1), f2) | (f1, Mul (CstI i, f2)) when f1 = f2 -> Add (CstI (i+1), f1) // i1 * e + i2 * e = i3 * e where i3 = i1 + i2 | (Mul (CstI i1, f1), Mul (CstI i2, f2)) when f1 = f2 -> Mul (CstI (i1 + i2), f1) // Move integers forward. | (e, CstI i) -> Add (CstI i, e) // Move integers even more forward. | (f1, Add (CstI i, f2)) -> Add (CstI i, Add (f1, f2)) // Further simplification not possible. | e -> Add e | Mul(e1,e2) -> match simplify2 e1 e2 with // Common multiplication of integers. | (CstI i1, CstI i2) -> CstI (i1 * i2) // 1 * e = e * 1 = e | (CstI 1, e) | (e, CstI 1) -> e // 0 * e = e * 0 = 0 | (CstI 0, e) | (e, CstI 0) -> CstI 0 // i1 * (i2 * e) = (i1 * i2) * e | (CstI i1, Mul (CstI i2, e)) -> Mul (CstI (i1 * i2), e) // i1 * (i2 + e) = i3 + i1 * e where i3 = i1 * i2 | (CstI i1, Add (CstI i2, e)) -> Add (CstI (i1 * i2), Mul (CstI i1, e)) // i1 * (i2 - e) = i3 - i1 * e where i3 = i1 * i2 | (CstI i1, Sub (CstI i2, e)) -> Sub (CstI (i1 * i2), Mul (CstI i1, e)) // Move integers forward. | (e, CstI i) -> Mul (CstI i, e) // Move integers even more forward. | (f1, Mul (CstI i, f2)) -> Mul (CstI i, Mul (f1, f2)) // Further simplification not possible. | e -> Mul e | Sub(e1,e2) -> match simplify2 e1 e2 with // Common subtraction of integers. | (CstI i1, CstI i2) -> CstI (i1 - i2) // e - 0 = e | (e, CstI 0) -> e // e - e = 0 | (x, y) when x = y -> CstI 0 // i1 - (i2 + e) = (i1 - i2) - e | (CstI i1, Add (CstI i2, e)) -> Sub (CstI (i1 - i2), e) // i1 - (i2 - e) = (i1 - i2) + e | (CstI i1, Sub (CstI i2, e)) -> Add (CstI (i1 - i2), e) // i1 * e - i2 * e = i3 * e where i3 = i1 - i2 | (Mul (CstI i1, f1), Mul (CstI i2, f2)) when f1 = f2 -> Mul (CstI (i1 - i2), f1) // i * e - e = e - i * e = (i + 1) * e | (Mul (CstI i, f1), f2) when f1 = f2 -> Sub (CstI (i-1), f1) // e - i * e = (1 - i) * e | (f1, Mul (CstI i, f2)) when f1 = f2 -> Sub (CstI (1-i), f1) // Move integers forward. | (e, CstI i) -> Sub(CstI i, e) // Further simplification not possible. | e -> Sub e and simplify2 e1 e2 = (simplify e1, simplify e2)