Solution

ID: past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2007/ia/paper-5/10/c/solution

Add a public override of toString in each concrete subclass. In TypeVar:
public String toString() {
    return "t" + id.toString();
}
In Arrow:
public String toString() {
    return "(" + from.toString() + " -> " + to.toString() + ")";
}
Inherited dynamic dispatch selects the proper method at every node of the abstract syntax tree. Full parentheses distinguish the domain and codomain nesting without relying on a reader's precedence convention. Repeated occurrences of one type variable use the same identifier, and distinct factory variables have distinct identifiers. For example, with the first three factory variables, the type from part (b) prints as ((t1 -> t2) -> (t2 -> t3)). The recursive textual form preserves both arrow structure and variable identity.

New to topics? Read the docs here!