public class ExprProblemInstanceOf {

    public static void main(String[] args) {
	new ExprProblemInstanceOf().test();
    }

    void test() {
	Expr e = new Add(new Lit(1), new Minus(new Lit(2), new Lit(0)));
	System.out.println(evaluate(e));
	System.out.println(print(e));
	System.out.println(print(simplify(e)));
    }

    interface Expr {
    }

    class Lit implements Expr {
	int value;

	Lit(int a) {
	    this.value = a;
	}
    }

    class Add implements Expr {
	Expr a, b;

	Add(Expr x, Expr y) {
	    this.a = x;
	    this.b = y;
	}
    }

    class Minus implements Expr {
	Expr a, b;

	Minus(Expr x, Expr y) {
	    this.a = x;
	    this.b = y;
	}
    }

    int evaluate(Expr e) {
	if (e instanceof Lit)
	    return ((Lit) e).value;
	if (e instanceof Add)
	    return evaluate(((Add) e).a) + evaluate(((Add) e).b);
	if (e instanceof Minus)
	    return evaluate(((Minus) e).a) - evaluate(((Minus) e).b);
	return 0;
    }

    String print(Expr e) {
	if (e instanceof Lit)
	    return Integer.toString(((Lit) e).value);
	if (e instanceof Add)
	    return "(" + print(((Add) e).a) + " + " + print(((Add) e).b) + ")";
	if (e instanceof Minus)
	    return "(" + print(((Minus) e).a) + " - " + print(((Minus) e).b)
		    + ")";
	return "";
    }

    Expr simplify(Expr e) {
	if (e instanceof Lit)
	    return e;
	if (e instanceof Add && ((Add) e).a instanceof Lit
		&& ((Lit) ((Add) e).a).value == 0)
	    return simplify(((Add) e).b);
	if (e instanceof Add && ((Add) e).b instanceof Lit
		&& ((Lit) ((Add) e).b).value == 0)
	    return simplify(((Add) e).a);
	if (e instanceof Add)
	    return new Add(simplify(((Add) e).a), simplify(((Add) e).b));
	if (e instanceof Minus && ((Minus) e).b instanceof Lit
		&& ((Lit) ((Minus) e).b).value == 0)
	    return simplify(((Minus) e).a);
	if (e instanceof Minus)
	    return new Minus(simplify(((Minus) e).a), simplify(((Minus) e).b));
	return e;
    }

}
