Since we will annotate some of our programs, we first introduce the syntax for comments. There are two types:
Prolog programs are built from valid Prolog data-structures. A program is a collection of predicates, and a predicate is a collection of clauses.
The idea of a clause is to define that something is true. The simplest form of a clause is the fact. For example, the following two are facts:
capital(london, england). brother(fred, jane). |
Syntactically, a fact is just a structure (or an atom) terminated by a full stop.
Generally, a clause has the form
Head :- Body.
where Head is a structure (or atom) and Body is a Goal, possibly with conjunctions and disjunctions like in the queries discussed above. The following is a clause
uncle(X,Z) :- brother(X,Y), parent(Y,Z). |
Logically, this can be read as a reverse implication
uncle(X,Z) ←— brother(X,Y) ∧ parent(Y,Z)
or, more precisely
∀ X ∀ Z: uncle(X,Z) ←— ∃ Y: brother(X,Y) ∧ parent(Y,Z)
stating that uncle(X,Z) is true if brother(X,Y) and parent(Y,Z) are true. Note that a fact is equivalent to a clause where the body is true:
brother(fred, jane) :- true. |
One or multiple clauses with the same head functor (same name and number of arguments) together form the definition of a predicate. Logically, multiple clauses are read as a disjunction, i.e. they define alternative ways in which the predicate can be true. The simplest case is a collection of alternative facts:
parent(abe, homer). parent(abe, herbert). parent(homer, bart). parent(marge, bart). |
The following defines the ancestor/2 predicate by giving two alternative clauses (rules):
ancestor(X,Y) :- parent(X,Y). ancestor(X,Y) :- parent(Z,Y), ancestor(X,Z). |
Remember that a clause can be read logically, with the :- taking the meaning of implication, and the comma separating goals read as a conjunction. The logical reading for several clauses of the same predicate is disjunction between the clauses. So the first ancestor rule above states that if X is a parent of Y, then this implies that X is an ancestor of Y. The second rule, which specifies another way X can be an ancestor of Y states that if some other person, Z, is the parent of Y, and X is an ancestor of Z, then this implies that X is also an ancestor of Y.