Skip to main content
โšก Calmops

Unification and Pattern Matching in Logic Programming

Introduction

Unification and pattern matching are the fundamental mechanisms that make logic programming work. They enable the system to:

  • Match queries against facts and rule heads
  • Bind variables to values
  • Determine if two terms can be made identical
  • Explore alternative solutions through backtracking

Understanding unification and pattern matching is essential for writing correct and efficient logic programs.

What is Unification?

Unification is the process of making two terms identical by finding appropriate variable bindings. It’s the core mechanism that enables pattern matching in logic programming.

Definition

Two terms unify if there exists a substitution (binding of variables to values) that makes them identical.

Example:

% parent(tom, bob) unifies with parent(X, Y)
% Substitution: X = tom, Y = bob

% parent(tom, bob) unifies with parent(tom, Z)
% Substitution: Z = bob

% parent(tom, bob) does NOT unify with parent(X, X)
% No substitution can make tom = bob

Unification Algorithm

The unification algorithm works as follows:

  1. If both terms are identical atoms or numbers: They unify with no substitution needed.

    tom unifies with tom โ†’ Success
    5 unifies with 5 โ†’ Success
    tom unifies with bob โ†’ Failure
    
  2. If one term is a variable: The variable unifies with the other term (if occurs check passes).

    X unifies with tom โ†’ X = tom
    X unifies with f(a, b) โ†’ X = f(a, b)
    
  3. If both terms are compound terms: They unify if:

    • They have the same functor and arity
    • Their corresponding arguments unify
    parent(tom, bob) unifies with parent(X, Y)
    โ†’ tom unifies with X (X = tom)
    โ†’ bob unifies with Y (Y = bob)
    โ†’ Success
    
  4. Otherwise: They don’t unify.

    parent(tom, bob) does NOT unify with grandparent(tom, bob)
    โ†’ Different functors (parent vs grandparent)
    

Occurs Check

The occurs check prevents infinite structures by checking if a variable appears in the term it’s being unified with.

% Without occurs check (standard Prolog)
X = f(X).  % Succeeds, creates infinite structure

% With occurs check (safer)
X = f(X).  % Fails, X cannot contain itself

Most Prolog systems don’t perform occurs check by default for performance reasons, but it’s important to be aware of this issue.

Pattern Matching

Pattern matching is the process of comparing a query or goal against facts and rule heads to find matches. Unification is the mechanism that enables pattern matching.

Basic Pattern Matching

Matching against facts:

% Facts
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).

% Query: ?- parent(tom, bob).
% Matching process:
% 1. Try to unify parent(tom, bob) with parent(tom, bob) โ†’ Success!
% Answer: yes

% Query: ?- parent(tom, X).
% Matching process:
% 1. Try to unify parent(tom, X) with parent(tom, bob)
%    โ†’ tom unifies with tom (success)
%    โ†’ X unifies with bob (X = bob)
% Answer: X = bob

Matching against rule heads:

% Rule
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).

% Query: ?- grandparent(tom, ann).
% Matching process:
% 1. Try to unify grandparent(tom, ann) with grandparent(X, Z)
%    โ†’ tom unifies with X (X = tom)
%    โ†’ ann unifies with Z (Z = ann)
% 2. Now try to prove the body with these bindings:
%    parent(tom, Y), parent(Y, ann)

Complex Pattern Matching

Matching compound terms:

% Facts
person(john, age(25), city(new_york)).
person(mary, age(30), city(london)).

% Query: ?- person(john, age(A), city(C)).
% Matching:
% 1. john unifies with john โ†’ Success
% 2. age(A) unifies with age(25) โ†’ A = 25
% 3. city(C) unifies with city(new_york) โ†’ C = new_york
% Answer: A = 25, C = new_york

Matching lists:

% Facts
list_member([1, 2, 3]).
list_member([a, b, c]).

% Query: ?- list_member([H|T]).
% Matching:
% 1. [H|T] unifies with [1, 2, 3]
%    โ†’ H = 1 (head)
%    โ†’ T = [2, 3] (tail)
% Answer: H = 1, T = [2, 3]

Unification Examples

Example 1: Simple Unification

% Query: ?- parent(tom, bob) = parent(X, Y).
% Unification:
% 1. parent unifies with parent (same functor)
% 2. tom unifies with X โ†’ X = tom
% 3. bob unifies with Y โ†’ Y = bob
% Answer: X = tom, Y = bob

Example 2: Recursive Unification

% Query: ?- f(a, g(b, c)) = f(X, g(Y, Z)).
% Unification:
% 1. f unifies with f (same functor)
% 2. a unifies with X โ†’ X = a
% 3. g(b, c) unifies with g(Y, Z)
%    โ†’ g unifies with g (same functor)
%    โ†’ b unifies with Y โ†’ Y = b
%    โ†’ c unifies with Z โ†’ Z = c
% Answer: X = a, Y = b, Z = c

Example 3: Failed Unification

% Query: ?- parent(tom, bob) = parent(tom, tom).
% Unification:
% 1. parent unifies with parent (same functor)
% 2. tom unifies with tom โ†’ Success
% 3. bob unifies with tom โ†’ FAILURE (bob โ‰  tom)
% Answer: no

Example 4: Variable Unification

% Query: ?- X = Y, Y = tom.
% Unification:
% 1. X = Y โ†’ X and Y are the same variable
% 2. Y = tom โ†’ Y = tom, so X = tom
% Answer: X = tom, Y = tom

Example 5: List Unification

% Query: ?- [H|T] = [1, 2, 3].
% Unification:
% 1. [H|T] unifies with [1, 2, 3]
%    โ†’ H = 1 (head)
%    โ†’ T = [2, 3] (tail)
% Answer: H = 1, T = [2, 3]

% Query: ?- [A, B|Rest] = [1, 2, 3, 4].
% Unification:
% 1. A = 1 (first element)
% 2. B = 2 (second element)
% 3. Rest = [3, 4] (remaining elements)
% Answer: A = 1, B = 2, Rest = [3, 4]

Pattern Matching in Action

Example 1: Finding Family Relationships

% Facts
parent(tom, bob).
parent(bob, ann).
parent(bob, pat).

% Query: ?- parent(X, bob).
% Pattern matching:
% 1. Try to match parent(X, bob) with parent(tom, bob)
%    โ†’ tom unifies with X (X = tom)
%    โ†’ bob unifies with bob (success)
% Answer: X = tom

% Query: ?- parent(bob, X).
% Pattern matching:
% 1. Try to match parent(bob, X) with parent(tom, bob) โ†’ Fails
% 2. Try to match parent(bob, X) with parent(bob, ann)
%    โ†’ bob unifies with bob (success)
%    โ†’ X unifies with ann (X = ann)
% Answer: X = ann (first solution)
% 3. Backtrack and try next fact: parent(bob, pat)
%    โ†’ X = pat (second solution)

Example 2: Matching Structured Data

% Facts
employee(john, department(engineering), salary(80000)).
employee(mary, department(sales), salary(60000)).
employee(bob, department(engineering), salary(75000)).

% Query: ?- employee(john, department(D), salary(S)).
% Pattern matching:
% 1. john unifies with john โ†’ Success
% 2. department(D) unifies with department(engineering)
%    โ†’ D = engineering
% 3. salary(S) unifies with salary(80000)
%    โ†’ S = 80000
% Answer: D = engineering, S = 80000

% Query: ?- employee(X, department(engineering), salary(S)).
% Pattern matching:
% 1. Try first fact: employee(john, department(engineering), salary(80000))
%    โ†’ X = john, S = 80000
% Answer: X = john, S = 80000 (first solution)
% 2. Backtrack and try next fact: employee(mary, ...) โ†’ Fails
% 3. Try next fact: employee(bob, department(engineering), salary(75000))
%    โ†’ X = bob, S = 75000
% Answer: X = bob, S = 75000 (second solution)

Example 3: Matching with Rules

% Facts
parent(tom, bob).
parent(bob, ann).

% Rule
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).

% Query: ?- grandparent(tom, ann).
% Pattern matching and unification:
% 1. Try to unify grandparent(tom, ann) with grandparent(X, Z)
%    โ†’ X = tom, Z = ann
% 2. Now try to prove the body: parent(tom, Y), parent(Y, ann)
% 3. Try to unify parent(tom, Y) with parent(tom, bob)
%    โ†’ Y = bob
% 4. Try to unify parent(bob, ann) with parent(bob, ann)
%    โ†’ Success!
% Answer: yes

Substitution and Variable Binding

A substitution is a mapping from variables to terms. When unification succeeds, it produces a substitution that binds variables to values.

Substitution Notation

% Substitution: {X = tom, Y = bob}
% This means: replace X with tom, replace Y with bob

% Original term: parent(X, Y)
% After substitution: parent(tom, bob)

Applying Substitutions

% Substitution: {X = tom, Y = bob, Z = ann}

% Apply to parent(X, Y)
% Result: parent(tom, bob)

% Apply to grandparent(X, Z)
% Result: grandparent(tom, ann)

% Apply to ancestor(X, Y)
% Result: ancestor(tom, bob)

Composing Substitutions

% Substitution 1: {X = Y}
% Substitution 2: {Y = tom}
% Composed: {X = tom, Y = tom}

% Original term: parent(X, Y)
% After substitution 1: parent(Y, Y)
% After substitution 2: parent(tom, tom)

Unification Failures

Understanding why unification fails is important for debugging logic programs.

Failure Reasons

Different functors:

% parent(tom, bob) does NOT unify with grandparent(tom, bob)
% Reason: Different functors (parent vs grandparent)

Different arities:

% parent(tom, bob) does NOT unify with parent(tom)
% Reason: Different arities (2 vs 1)

Different constants:

% parent(tom, bob) does NOT unify with parent(tom, ann)
% Reason: bob โ‰  ann

Occurs check failure:

% X does NOT unify with f(X) (with occurs check)
% Reason: X appears in f(X)

Unification in Queries

Query Execution with Unification

% Facts
parent(tom, bob).
parent(bob, ann).

% Query: ?- parent(X, Y).
% Execution:
% 1. Unify parent(X, Y) with parent(tom, bob)
%    โ†’ X = tom, Y = bob
%    โ†’ Return first solution
% 2. User asks for more (;)
% 3. Backtrack and unify parent(X, Y) with parent(bob, ann)
%    โ†’ X = bob, Y = ann
%    โ†’ Return second solution
% 4. No more facts
%    โ†’ Done

Query Execution with Rules

% Facts
parent(tom, bob).
parent(bob, ann).

% Rule
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).

% Query: ?- grandparent(X, Y).
% Execution:
% 1. Unify grandparent(X, Y) with grandparent(X, Z) (rule head)
%    โ†’ X = X, Y = Z (no new bindings)
% 2. Try to prove body: parent(X, Y), parent(Y, ann)
%    Wait, we need to be more careful here...
%
% Actually:
% 1. Unify grandparent(X, Y) with grandparent(X1, Z1) (rule head with fresh variables)
%    โ†’ X = X1, Y = Z1
% 2. Try to prove body: parent(X1, Y1), parent(Y1, Z1)
% 3. Unify parent(X1, Y1) with parent(tom, bob)
%    โ†’ X1 = tom, Y1 = bob
% 4. Unify parent(Y1, Z1) with parent(bob, ann)
%    โ†’ Y1 = bob (already bound), Z1 = ann
% 5. Success! X = tom, Y = ann

Best Practices

1. Understand Variable Scope

Variables in a clause are local to that clause. Each time a rule is used, fresh variables are created.

% Rule
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).

% Query 1: ?- grandparent(tom, ann).
% Uses fresh variables: X, Y, Z

% Query 2: ?- grandparent(bob, jim).
% Uses fresh variables: X, Y, Z (different from Query 1)

2. Use Meaningful Variable Names

% Good
grandparent(GrandParent, GrandChild) :- 
    parent(GrandParent, Parent), 
    parent(Parent, GrandChild).

% Less clear
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).

3. Be Aware of Unification Order

The order of unification can affect performance.

% Less efficient: Unifies with all facts first
?- parent(X, Y), age(X, A), A > 50.

% More efficient: Filters early
?- age(X, A), A > 50, parent(X, Y).

4. Avoid Infinite Unification

Be careful with recursive rules to avoid infinite loops.

% Bad: Can cause infinite recursion
ancestor(X, Y) :- ancestor(X, Z), parent(Z, Y).

% Good: Base case first
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).

Glossary

  • Unification: Process of making two terms identical through variable binding
  • Pattern matching: Comparing a query against facts and rules using unification
  • Substitution: Mapping from variables to terms
  • Variable binding: Assigning a value to a variable
  • Occurs check: Checking if a variable appears in the term it’s being unified with
  • Functor: The name of a compound term (e.g., parent in parent(tom, bob))
  • Arity: The number of arguments a functor takes
  • Ground term: A term containing no variables
  • Compound term: A term with a functor and arguments
  • Atom: A basic constant (e.g., tom, bob)
  • Unification failure: When two terms cannot be made identical
  • Fresh variables: New variables created each time a rule is used

Practice Problems

Problem 1: Unification

Which of the following pairs unify? For those that do, show the substitution.

  1. parent(tom, bob) with parent(X, Y)
  2. parent(tom, bob) with parent(tom, tom)
  3. f(a, g(b)) with f(X, g(Y))
  4. [1, 2, 3] with [H|T]
  5. X with f(X) (with occurs check)

Solution:

  1. โœ“ Unifies: X = tom, Y = bob
  2. โœ— Does not unify (bob โ‰  tom)
  3. โœ“ Unifies: X = a, Y = b
  4. โœ“ Unifies: H = 1, T = [2, 3]
  5. โœ— Does not unify (occurs check fails)

Problem 2: Pattern Matching

Given the facts:

employee(alice, engineering, 80000).
employee(bob, sales, 60000).
employee(charlie, engineering, 75000).

What are the results of these queries?

  1. ?- employee(alice, D, S).
  2. ?- employee(X, engineering, S).
  3. ?- employee(X, Y, 80000).

Solution:

  1. D = engineering, S = 80000
  2. X = alice, S = 80000 ; X = charlie, S = 75000
  3. X = alice, Y = engineering

Problem 3: Unification with Rules

Given:

parent(tom, bob).
parent(bob, ann).
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).

Trace the unification process for: ?- grandparent(tom, ann).

Solution:

  1. Unify grandparent(tom, ann) with grandparent(X, Z) โ†’ X = tom, Z = ann
  2. Try to prove parent(tom, Y), parent(Y, ann)
  3. Unify parent(tom, Y) with parent(tom, bob) โ†’ Y = bob
  4. Unify parent(bob, ann) with parent(bob, ann) โ†’ Success!
  5. Answer: yes

Problem 4: Complex Unification

Given:

person(john, info(age(25), city(new_york))).
person(mary, info(age(30), city(london))).

What are the results of:

  1. ?- person(john, info(age(A), city(C))).
  2. ?- person(X, info(age(30), city(Y))).

Solution:

  1. A = 25, C = new_york
  2. X = mary, Y = london

Online Platforms

Interactive Tools

  • “Programming in Prolog” by Clocksin & Mellish - Classic introduction
  • “The Art of Prolog” by Sterling & Shapiro - Advanced techniques
  • “Logic Programming: The 1st and 2nd Conferences” - Historical perspective
  • “Prolog and Natural Language Analysis” by Pereira & Shieber - NLP applications
  • “Constraint Logic Programming” by Jaffar & Maher - CLP overview

Academic Journals

Software Tools

Conclusion

Unification and pattern matching are the core mechanisms that enable logic programming:

  • Unification makes two terms identical through variable binding
  • Pattern matching uses unification to compare queries against facts and rules
  • Substitutions track variable bindings throughout computation
  • Backtracking explores alternative unifications when one fails

Mastering unification and pattern matching is essential for understanding how logic programs work and for writing correct and efficient programs.

In the next level, we’ll explore more advanced topics in formal systems and automated reasoning.


Previous Article: Facts, Rules, and Queries

Comments