Memra

Unification, substitution sets, and the most general unifier

◈ 4 cards

Explain why unification is needed, compute an mgu by hand and in code (with the occurs check), and know why Skolemization removes ∃ before unification.

Why matching needs an algorithm

Modus ponens requires the antecedent of a rule to match a known fact. In propositional logic matching is trivial — two formulas are identical or they are not. In predicate calculus, variables make matching non-trivial: should match by binding . Unification is the algorithm that finds the variable substitutions making two expressions syntactically identical — it is the computational core of Prolog and of resolution.

Substitutions and the mgu

A substitution binds variables to terms, written (" for "). The set of bindings carried through a chain of inferences is the substitution set, and consistency must hold across it: once is bound to , every later in scope is .

When several substitutions could unify two expressions, we want the most general unifier (mgu) — the least committed one, introducing fresh variables rather than arbitrary constants. Unifying with : the substitution works but needlessly forces both to ; the mgu only forces them to be equal, leaving every future match open. Any other unifier can be obtained from the mgu by a further substitution. The mgu is unique up to renaming variables.

The algorithm (list form) and the occurs check

The textbook writes expressions as lists with the predicate/function name as head, so is ['p', 'X', ['f', 'Y']] — this erases the predicate/function distinction and makes matching pure list recursion. The cases:

  1. Identical expressions unify with the empty substitution {}.
  2. A variable not occurring in the other expression unifies via .
  3. Two lists unify by recursively unifying their heads, applying that substitution to the tails, recursively unifying the tails, and composing the two substitution sets.

The two failure cases are mismatched constants (e.g. a vs b) and the occurs check: a variable may not unify with a term containing that same variable with would build the infinite term . The occurs check guards against it.

Substitution composition applies to the bindings of then adds ; it is associative but not commutative — order matters.

Worked example: unify with $p(a, f(b))$

Heads p = p ✓. First arg: vs → bind . Apply to the rest, then second arg: vs → heads f=f, then vs → bind . Compose: the mgu is , i.e. {X: a, Y: b}. By contrast vs $p(a, b)$ binds $X = a$ from the first argument, but then the second argument needs — inconsistent — so unification returns FAIL. The Python implementation below prints exactly that.

stepcomparebindssubstitution sofarheadsp vs p{}arg 1X vs aa/X{a/X}arg 2f(Y) vs f(b){a/X}↳ innerY vs bb/Y{a/X, b/Y}mgu = {X: a, Y: b}. Occurs check: X vs f(X) is refused, not bound.
Unification is list recursion with an accumulator: compare heads, bind what you can, <em>apply the bindings so far to the remaining arguments</em>, recurse. That last part is what makes <code>p(X, X)</code> vs <code>p(a, b)</code> fail — argument one binds X to a, so argument two is comparing <code>a</code> with <code>b</code>, two different constants.
NORMAL ~/memra/learn/comp-456/unification-substitution-mgu utf-8 LF