type Expr =
    | Num(Int)
    | Add(Expr, Expr)
    | Sub(Expr, Expr)
    | Mul(Expr, Expr)

fn eval(e: Expr): Int =
    match e {
    Num(n) => n,
    Add(a, b) => eval(a) + eval(b),
    Sub(a, b) => eval(a) - eval(b),
    Mul(a, b) => eval(a) * eval(b),
}

fn showExpr(e: Expr): String =
    match e {
    Num(n) => toString(n),
    Add(a, b) => "(" + showExpr(a) + " + " + showExpr(b) + ")",
    Sub(a, b) => "(" + showExpr(a) + " - " + showExpr(b) + ")",
    Mul(a, b) => "(" + showExpr(a) + " * " + showExpr(b) + ")",
}

fn evalAndPrint(e: Expr): Unit with {Console} = {
    Console.print("Evaluating: " + showExpr(e))
    Console.print("Result: " + toString(eval(e)))
}

fn main(): Unit with {Console} = {
    let e1 = Add(Num(2), Num(3))
    evalAndPrint(e1)
    let e2 = Mul(Add(Num(1), Num(2)), Add(Num(3), Num(4)))
    evalAndPrint(e2)
    let e3 = Sub(Num(10), Mul(Num(2), Num(3)))
    evalAndPrint(e3)
}

let output = run main() with {}
