Memra

Facts, rules, queries, and the closed-world assumption

Read a clause declaratively, write facts and head :- body rules, pose a query, and understand why Prolog treats unprovable as false (negation-as-failure).

Prolog is logic you can run

Python is our runtime, but the COMP 456 exam (Q3) and three of the four assignments are written in Prolog. Prolog is *declarative*: you state what is true, and the interpreter searches for how to prove a goal. A Prolog program is just a set of Horn clauses (Chapter 14), and running a query is resolution-based theorem proving driven by unification (the algorithm from M1).

There are exactly three clause forms, and they map onto the Horn-clause theory one-for-one:

- A fact — an unconditional truth. parent(tom, bob). ("tom is a parent of bob"). - A rulehead :- body, read "head is true *if* body is true". The :- is ("if"), and the comma in the body is conjunction (). - A query (goal) — what you ask at the ?- prompt. The interpreter tries to prove it.

The case convention (the #1 student slip)

In this textbook's notation and in Prolog, lowercase = constant (a specific named object: tom, bob) and an initial uppercase letter = variable (stands for any object: X, Person). Students reverse this constantly — guard against it.

Worked example — a family tree

Facts about who is a parent of whom, then a *rule* defining grandparent in terms of two parent steps:

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

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

Read the rule declaratively: "X is a grandparent of Y if X is a parent of some Z and that Z is a parent of Y." The shared variable Z is the bridge — unification must bind Z consistently in *both* parent goals. Now ask:

?- grandparent(tom, Who).
Who = ann ;
Who = pat.

The interpreter unifies grandparent(tom, Who) with the rule head (binding X = tom, Y = Who), then proves the body left to right: parent(tom, Z) succeeds with Z = bob, then parent(bob, Who) succeeds with Who = ann. Typing ; asks for the next solution; backtracking re-tries parent(bob, Who) and finds Who = pat.

The closed-world assumption

Prolog assumes its database is complete: anything it cannot prove is taken to be false. This closed-world assumption (CWA) is what lets Prolog implement *negation-as-failure* with \+: \+ parent(tom, sue) succeeds precisely because Prolog *fails* to prove parent(tom, sue). The catch (and a favourite exam trap): unprovable means "false" even when the truth is merely *unknown* — Prolog cannot tell a false fact from a missing one.

NORMAL ~/memra/learn/comp-456/prolog-facts-rules-queries utf-8 LF