sealed interface Expr {

    record Val(int value) implements Expr {}
    record Sum(Expr left, Expr right) implements Expr {}
    record Diff(Expr left, Expr right) implements Expr {}
    record Times(Expr left, Expr right) implements Expr {}

    default int evaluate() {
        return switch (this) {
            case Val(var value) -> value;
            case Sum(var left, var right) -> left.evaluate() + right.evaluate();
            case Diff(var left, var right) -> left.evaluate() - right.evaluate();
            case Times(var left, var right) -> left.evaluate() * right.evaluate();
        };
    }

    default String asString() {
        return switch (this) {
            case Val(var value) -> String.valueOf(value);
            case Sum(var left, var right) -> "(" + left.asString() + "+" + right.asString() + ")";
            case Diff(var left, var right) -> "(" + left.asString() + "-" + right.asString() + ")";
            case Times(var left, var right) -> "(" + left.asString() + "*" + right.asString() + ")";
        };
    }

    default void print() {
        System.out.println(asString() + "=" + evaluate());
    }

    static Expr val(int value) {
        return new Val(value);
    }

    static Expr sum(Expr left, Expr right) {
        return new Sum(left, right);
    }

    static Expr diff(Expr left, Expr right) {
        return new Diff(left, right);
    }

    static Expr times(Expr left, Expr right) {
        return new Times(left, right);
    }

    static void main() {
        sum(val(1), val(2)).print();
        times(diff(val(10), val(8)), val(2)).print();
    }
}
