Previous Up Next

3.4  Defining Your Own Predicates

3.4.1  Comments

Since we will annotate some of our programs, we first introduce the syntax for comments. There are two types:

Block comment
The comment is enclosed between the delimiters /* and */. Such comments can span multiple lines, and may be conveniently used to comment out unused code.
Line comment
Anything following and including ’%’ in a line is taken as a comment (unless the ’%’ character is part of a quoted atom or string).

3.4.2  Clauses and Predicates

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

XZ: 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.

It is also important to remember that the scope of a variable name only extends over the clause in which it is in, so any variables with the same name in the same clause refer to the same variable, but variables which occur in different clauses are different even if they have been written with the same name.

Previous Up Next