First-order unification 2026-10-20
First-order unification seeks substitutions making first-order terms identical. Constructor decomposition and the occurs check produce a most general unifier when one exists.
Occurs check 2026-10-14
The occurs check tests whether a type variable occurs inside the expression proposed as its replacement during type unification. After discarding a trivial equation such as , solving by a type substitution requires that not occur in . Thus is permitted when and are distinct, but is rejected in our finite simple type grammar.
There is a short reason for the rejection. If a finite replacement for existed, with replacement for , the equation would become . The right side's abstract syntax tree has one new arrow node plus the nodes of and , so it has strictly more nodes than . Equal finite type expressions cannot have different sizes. Recursive types are a different design: they explicitly describe self-reference and specify how it interacts with typing judgments.
Past exam of the mathematics course of the University of Cambridge 2007 ia Paper 5 10 b Solution Created 2026-09-24 Updated 2026-10-14
Introduce a checked exception class, for example in its own source file:Declare the required abstract method in Within the nested Within the nested The parameter denotes an actual non-null type variable returned by the factory; checking object identity distinguishes different variables without confusing their printed names. Structural induction on the abstract syntax tree proves the occurs check: a variable node contains the queried variable exactly when the identities match, and an arrow contains it exactly when either component does. The first detected occurrence throws and propagates the checked exception; normal return proves absence. Both subclass methods must declare the exception, and callers must catch or declare it.
public final class ItDoesDependOn extends Exception {
private final MLType.TypeVar variable;
public ItDoesDependOn(MLType.TypeVar variable) {
this.variable = variable;
}
public MLType.TypeVar getVariable() { return variable; }
}MLType:public abstract void mustNotDependOn(TypeVar a)
throws ItDoesDependOn;TypeVar class implement it by an identity check:public void mustNotDependOn(TypeVar a) throws ItDoesDependOn {
if (this == a) throw new ItDoesDependOn(a);
}Arrow class implement it recursively:public void mustNotDependOn(TypeVar a) throws ItDoesDependOn {
from.mustNotDependOn(a);
to.mustNotDependOn(a);
}For , either recursive branch detects each of , whereas a distinct is absent and the call returns. A recursive identity-based occurs check throws exactly when the queried variable occurs.
Let
x :: a and g :: a -> b, as required by the inner application g x. Using g x as the next argument of that same g forces b = a. Thus g (g x) :: a. Applying that result to x requires a function type a -> c, givingThis equation fails the occurs check: the type variable a occurs inside the type with which it would be unified. These constraints have no solution in the Hindley-Milner type system. Therefore the definition has no type in ordinary Haskell. The obstruction is to type inference, independently of which particular values might later be supplied. Type unification Created 2026-10-14 Updated 2026-10-25
Type unification finds a type substitution making specified type expressions equal, or reports incompatible constraints. In our simple type grammar, matching two function types reduces to matching their argument types and their result types. Distinct base types
int and bool fail to match; solving a type variable against a nontrivial type expression uses the occurs check.// Target: computer-science.bigb
Unification 2026-10-20
Unification seeks substitutions for variables that make symbolic terms identical. First-order unification compares matching constructors recursively; an occurs check rejects substitutions that would make a variable contain itself.