Pprolog
Pprolog
sunny. /* It is sunny. */
father(john, peter). /* John is the father of Peter. */
father(john, mary).
father(david, liza).
father(david, john).
father(jack, susan).
father(jack, ray).
mother(susan, peter). /* Susan is the mother of Peter. */
mother(susan, mary).
mother(amy, liza).
mother(amy, john).
mother(karen, susan).
mother(karen, ray).
loves(john, susan). /* John loves Susan. */
b1([p, 2, q], p). /* No special meaning. */
As you can see, a Prolog program consists of a number of clauses, each ended with a fullstop ( . ). Each clause
is either a fact or a rule.
An atom is a group of alphanumeric characters (the underscore character is also considered as an alphanumeric
character) starting with a small letter. In the above example, father, mother, david, yeye, b1, p, a, etc., are
atoms. Some atoms are constants while others are predicates.
A variable is a group of alphanumeric characters starting with a capital letter or the underscore ( _ ) character.
In the above example, X, Temp, Y, A1, A, B and C are variables. Variables (as well as constants) need not be
declared in Prolog.
Constants and variables are called terms.
Prolog is case sensitive. Therefore abc and aBc are different (although both of them are atoms).
Apart from atoms and variables, Prolog can also process numbers.
Atoms, variables and numbers can be enclosed by square brackets ( [] ) to form a list.
Comments are enclosed by the delimiters /* and */.
>>A Prolog program consists of a number of clauses. Each clause is either a fact or a rule. After a Prolog
program is loaded (or consulted) in a Prolog interpreter, users can submit goals or queries, and the Prolog
intepreter will give results (answers) according to the facts and rules.
Facts
A fact must start with a predicate (which is an atom) and end with a fullstop. The predicate may be followed by
one or more arguments which are enclosed by parentheses. The arguments can be atoms (in this case, these
atoms are treated as constants), numbers, variables or lists. Arguments are separated by commas.
If we consider the arguments in a fact to be objects, then the predicate of the fact describes a property of the
objects.
In a Prolog program, a presence of a fact indicates a statement that is true. An absence of a fact indicates a
statement that is not true. See the following example:
Program 2: A Prolog program with facts only
sunny.
father(john, peter).
father(john, mary).
mother(susan, peter).
Goals/Queries and their results (in red):
?- sunny. /* The response is yes because the fact "sunny." is present.
*/
yes
?- rainy. /* There is an error because there is no predicate "rainy". */
Erroneous result.
?- father(john, mary).
yes
?- mother(susan, mary). /* This cannot be deduced. */
no
?- father(john, susan). /* This cannot be deduced. */
no
Rules
A rule can be viewed as an extension of a fact with added conditions that also have to be satisfied for it to be
true. It consists of two parts. The first part is similar to a fact (a predicate with arguments). The second part
consists of other clauses (facts or rules which are separated by commas) which must all be true for the rule itself
to be true. These two parts are separated by ":-". You may interpret this operator as "if" in English.
See the following example:
Program 3: A program describes the relationships of the members in a family
father(jack, susan). /* Fact 1 */
father(jack, ray). /* Fact 2 */
father(david, liza). /* Fact 3 */
father(david, john). /* Fact 4 */
father(john, peter). /* Fact 5 */
father(john, mary). /* Fact 6 */
mother(karen, susan). /* Fact 7 */
mother(karen, ray). /* Fact 8 */
mother(amy, liza). /* Fact 9 */
mother(amy, john). /* Fact 10 */
mother(susan, peter). /* Fact 11 */
mother(susan, mary). /* Fact 12 */
?- 4 = 4.
yes Obvious.
?- 4 is 4.
yes Obvious.
?- 4 = 1 + 3. The answer is no because the left hand side (4) is not identical to right
no hand side (1 + 3).
?- 4 is 1 + 3.
yes The value of left hand side is equal to the value of right hand side.
list
A list is an ordered sequence of objects and lists. In Prolog, a list is written as its elements separated by commas
and enclosed in brackets. For example:
[] This is an empty list.
[peter, 4, abc, X]
This is a list containing four elements. There is no restrictions on the number of
variables and constants in the list.
[a, b, [c, d], e]
This list contains four elements. The third element is a list. This example shows
that a list can also be an element of another list.
Head and tail
The head of a list is the first element in the list. The tail of a list is the list that remains after the first element is
removed. For example:
List Head Tail
[] undefined undefined
[a] a []
[a, b] a [b]
[[a, b], c] [a, b] [c]
[[a, b], [c, d]] [a, b] [[c, d]]
A list with X as the head and Y as the tail can be expressed as [X | Y]. See the following examples.
Examples
Assume that the following program is consulted:
Program 5: A program about lists
head([H | T], H). /* R1 */
tail([H | T], T). /* R2 */
list([H | T], H, T). /* R3 */
max([H], H). /* R4 */
max([H | T], H) :- max(T, X), H >= X. /* R5 */
max([H | T], X) :- max(T, X), H < X. /* R6 */
Finding heads and tails
The following queries make use of facts R1 through R3 and are quite obvious.
Query Overall output
?- head([], X). no
?- list([], X, Y). no
?- head([a, b, c, d], X). X = a
?- tail([a], X). X = []
X = a
?- list([a, b], X, Y).
Y = [b]
Finding maximum value
Note: In each step of the process of deduction, there may be more than one subgoals to be processed. In this
case, only the first subgoal is considered. If there is a rule that can be applied to it, it is replaced by those
subgoals found in the applied rule. If it satisfies a fact, it is removed. If no rules or facts can be applied, we have
to backtrack.
Sample query:
?- max([3, 5, 2, 4], A).
Rules or
Bindings of
Level Results of deduction facts to
variables
be applied
Original max([3, 5, 2, 4], A).
R5 A =3
query
1 max([5, 2, 4], X), 3 >= X. R5 X=5
2 max([2, 4], X), 5 >= X, 3 >= 5. R5 X=2
3 max([4], X), 2 >= X, 5 >= 2, 3 >= 5. R4 X=4
4 2 >= 4, 5 >= 2, 3 >= 5. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 >= 2, 3 >= 5. R5 X=4
4 max([], X), 2 >= 4, 5 >= 2, 3 >= 5. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 >= 2, 3 >= 5. R6 -
4 max([], X), 4 < X, 2 >= 4, 5 >= 2, 3 >= 5. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 >= 2, 3 >= 5. Failed! Backtracks.
2 max([2, 4], X), 5 >= X, 3 >= 5. R6 -
3 max([4], X), 2 < X, 5 >= X, 3 >= 5. R4 X=4
4 2 < 4, 5 >= 4, 3 >= 5. Satisfied.
5 5 >= 4, 3 >= 5. Satisfied.
6 3 >= 5. Failed! Backtracks.
5 5 >= 4, 3 >= 5. Failed! Backtracks.
4 2 < 4, 5 >= 4, 3 >= 5. Failed! Backtracks.
3 max([4], X), 2 < X, 5 >= X, 3 >= 5. R6 -
4 max([], X), 4 < X, 2 < X, 5 >= X, 3 >= 5. Failed! Backtracks.
3 max([4], X), 2 < X, 5 >= X, 3 >= 5. Failed! Backtracks.
2 max([2, 4], X), 5 >= X, 3 >= 5. Failed! Backtracks.
1 max([5, 2, 4], X), 3 >= X. R6 -
2 max([2, 4], X), 5 < X, 3 >= X. R5 X=2
3 max([4], X), 2 >= X, 5 < 2, 3 >= 2. R4 X=4
4 2 >= 4, 5 < 2, 3 >= 2. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 < 2, 3 >= 2. R5 X=4
4 max([], X), 4 >= X, 2 >= 4, 5 < 2, 3 >= 2. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 < 2, 3 >= 2. R6 -
4 max([], X), 4 < X, 2 >= X, 5 < 2, 3 >= 2. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 < 2, 3 >= 2. Failed! Backtracks.
2 max([2, 4], X), 5 < X, 3 >= X. R6 -
3 max([4], X), 2 < X, 5 < X, 3 >= X. R4 X=4
4 2 < 4, 5 < 4, 3 >= 4. Satisfied.
5 5 < 4, 3 >= 4. Failed! Backtracks.
4 2 < 4, 5 < 4, 3 >= 4. Failed! Backtracks.
3 max([4], X), 2 < X, 5 < X, 3 >= X. R5 X=4
4 max([], X), 2 < 4, 5 < 4, 3 >= 4. Failed! Backtracks.
3 max([4], X), 2 < X, 5 < X, 3 >= X. R6 -
4 max([], X), 4 < X, 2 < X, 5 < X, 3 >= X. Failed! Backtracks.
3 max([4], X), 2 < X, 5 < X, 3 >= X. Failed! Backtracks.
2 max([2, 4], X), 5 < X, 3 >= X. Failed! Backtracks.
1 max([5, 2, 4], X), 3 >= X. Failed! Backtracks.
Original max([3, 5, 2, 4], A). R6 -
goal
1 max([5, 2, 4], A), 3 < A. R5 A =5
2 max([2, 4], X), 5 >= X, 3 < 5. R5 X =2
3 max([4], X), 2 >= X, 5 >= 2, 3 < 5. R4 X=4
4 2 >= 4, 5 >= 2, 3 < 5. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 >= 2, 3 < 5. R5 X=4
4 max([], X), 4 >= X, 2 >= 4, 5 >= 2, 3 < 5. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 >= 2, 3 < 5. R6 -
4 max([], X), 4 < X, 2 >= X, 5 >= 2, 3 < 5. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 >= 2, 3 < 5. Failed! Backtracks.
2 max([2, 4], X), 5 >= X, 3 < 5. R6 -
3 max([4], X), 2 < X, 5 >= X, 3 < 5. R4 X=4
4 2 < 4, 5 >= 2, 3 < 5. Satisfied.
5 5 >= 2, 3 < 5. Satisfied.
Satisfied!
6 3 < 5. Output: A = 5
Then backtracks.
5 5 >= 2, 3 < 5. Failed! Backtracks.
4 2 < 4, 5 >= 2, 3 < 5. Failed! Backtracks.
3 max([4], X), 2 < X, 5 >= 2, 3 < 5. R5 X=4
4 max([], X), X >= 4, 2 < 4, 5 >= 2, 3 < 5. Failed! Backtracks.
3 max([4], X), 2 < X, 5 >= 2, 3 < 5. R6 -
4 max([], X), 4 < X, 2 < X, 5 >= 2, 3 < 5. Failed! Backtracks.
3 max([4], X), 2 < X, 5 >= 2, 3 < 5. Failed! Backtracks.
2 max([2, 4], X), 5 >= X, 3 < 5. Failed! Backtracks.
1 max([5, 2, 4], A), 3 < A. R6 -
2 max([2, 4], A), 5 < A, 3 < A. R5 A=2
3 max([4], X), 2 >= X, 5 < 2, 3 < 2. R4 X=4
4 2 >= 4, 5 < 2, 3 < 2. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 < 2, 3 < 2. R5 X=4
4 max([], X), 4 >= X, 2 >= 4, 5 < 2, 3 < 2. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 < 2, 3 < 2. R6 -
4 max([], X), 4 < X, 2 >= X, 5 < 2, 3 < 2. Failed! Backtracks.
3 max([4], X), 2 >= X, 5 < 2, 3 < 2. Failed! Backtracks.
2 max([2, 4], A), 5 < A, 3 < A. R6 -
3 max([4], A), 2 < A, 5 < A, 3 < A. R4 A=4
4 2 < 4, 5 < 4, 3 < 4. Succeeded.
5 5 < 4, 3 < 4. Failed! Backtracks.
4 2 < 4, 5 < 4, 3 < 4. Failed! Backtracks.
3 max([4], A), 2 < A, 5 < A, 3 < A. R5 A=4
4 max([], X), 4 >= X, 2 < 4, 5 < 4, 3 < 4. Failed! Backtracks.
3 max([4], A), 2 < A, 5 < A, 3 < A. R6 -
4 max([], A), 4 < A, 2 < A, 5 < A, 3 < A. Failed! Backtracks.
3 max([4], A), 2 < A, 5 < A, 3 < A. Failed! Backtracks.
2 max([2, 4], A), 5 < A, 3 < A. Failed! Backtracks.
1 max([5, 2, 4], A), 3 < A. Failed! Backtracks.
Failed! There are no more
Original max([3, 5, 2, 4], A).
rules or facts that can be
goal
applied.
Overall A = 5
output
Overview
What is the Prolog interpreter doing during the process of deduction (replying to a query or searching to achieve
a goal)?
1. A Prolog program is consulted and the facts and rules in the program are loaded into the knowledge
database.
2. When a query or goal is given, the Prolog interpreter seaches the knowledge database from top to
bottom to find any facts or rules match with the query or goal.
3. If a match is found, the search for answers to the query succeeds or the goal is true. The values of any
variables found are given.
4. If the user asks for further solutions (e.g by entering a semicolon in some Prolog interpreter), the Prolog
interpreter continues searching. It keeps track of the facts and the rules which have been searched. When
it can find no more solutions, it says no and the search ends.
A detailed description of Step 2
The Prolog interpreter starts with the goal/query and works backward by identifying the facts and the rules (in
the knowledge database) from which the goal can be derived. This can be done by the expansion of a goal by
applying a rule and the reduction of a goal by applying a fact. You will see the process of deduction in the
example below.
Unification
Unification is the derivation of a new rule from a given rule through the binding of variables.
In order to match a goal or a query, any variable encountered is substituted with the value of an appropriate
constant (called binding).
Backtracking
Sometimes there are more than one fact/rule which can be applied to a goal/query. In this case, the fact/rule
which appears first in the knowledge database will be applied first. The other applicable facts or rules will be
applied later such that all possible solutions are found. This process is known as backtracking.
Examples
We will use the following program and some queries to explain the process of deduction.
Note: In each step of the process of deduction, there may be more than one subgoals to be processed. In this
case, only the first subgoal is considered. If there is a rule that can be applied to it, it is replaced by those
subgoals found in the applied rule. If it satisfies a fact, it is removed. If no rules or facts can be applied, we have
to backtrack.
Program 4: A program about some computers, installed software and some users
spec(comp1, pc, 32). /* Fact 1 */
spec(comp2, mac, 128). /* Fact 2 */
spec(comp3, pc, 64). /* Fact 3 */
runs(pc, movie_edit, 96). /* Fact 4 */
runs(pc, vb, 16). /* Fact 5 */
runs(pc, cpp, 28). /* Fact 6 */
runs(mac, vb, 24). /* Fact 7 */
runs(mac, prolog, 128). /* Fact 8 */
access(judy, comp1). /* Fact 9 */
access(peter, comp3). /* Fact 10 */
access(david, comp1). /* Fact 11 */
access(david, comp2). /* Fact 12 */
can_use(P, SW) :- access(P, Comp), can_run(Comp, SW). /* Rule 1 */
can_run(Comp, SW) :- spec(Comp, CompType, MemAvail),
runs(CompType, SW, MemNeeded),
MemAvail >= MemNeeded. /* Rule 2 */
Can Judy use VB?
?- can_use(judy, vb).
Level Results of deduction Rules or Bindings of
facts to variables
be applied
can_use(judy, vb).
In order that the original goal (can_use(judy, vb)) is true, according
to Rule 1, the conditions in the rule must be true (i.e. access(judy,
Original Comp) and can_run(Comp, vb) for some Comp). Therefore the goal can P = judy
be reduced as shown below. Rule 1
goal SW = vb
In order to apply Rule 1 to the goal, a unification is done by binding (i.e.
assigning) the value judy to the variable P and binding the value vb to
the variable SW.
access(judy, Comp), can_run(Comp, vb).
After unification, access(judy, comp1) is found to be true (from Fact Comp =
1 9). Therefore, whether the original goal is true or not depends on only Fact 9
comp1
whether can_run(comp1, vb) is true or not.
2 can_run(comp1, vb). Rule 2 -
4
runs(pc, vb, MemNeeded),
Fact 5 MemNeeded =
32 >= MemNeeded. 16
32 >=16.
The above is true, and so we can deduce that subgoals at level 4 is true, Satisfied!
5
and hence those at levels 3, 2, 1 and the original goal. Output: yes
Overall yes
output
Can David use Prolog?
?- can_use(david, prolog).
This goal demonstrates backtracking.
Rules or
Bindings of
Level Results of deduction facts to
variables
be applied
Original can_use(david, prolog). P = david
Rule 1
goal SW = prolog
access(david, Comp), can_run(Comp, prolog).
Both Fact 11 and Fact 12 are applicable. Since Fact 11 comes before Comp =
1 Fact 11
comp1
Fact 12, Fact 11 is tried first.
2 can_run(comp1, prolog). Rule 2 -
spec(comp1, CompType, MemAvail),
CompType =
pc
3 runs(CompType, prolog, MemNeeded), Fact 1
MemAvail >= MemNeeded. MemAvail =
32
runs(pc, prolog, MemNeeded),
32 >= MemNeeded.
4 Failed! Backtracks.
No rules or facts can further be applied. Backtracking is done here.
spec(comp1, CompType, MemAvail),
3 runs(CompType, prolog, MemNeeded), Failed! Backtracks.
MemAvail >= MemNeeded.
There is no applicable rules or facts that were not applied to these
subgoals before. So backtracking has to be done.
2 can_run(comp1, prolog). Failed! Backtracks.
access(david, Comp), can_run(Comp, prolog).
Comp =
1 Fact 11 has been used. Now we try Fact 12. Fact 12 comp2
4
runs(mac, prolog, MemNeeded),
Fact 8 MemNeeded =
128 >= MemNeeded. 128
Satisfied!
5 128 >= 128.
Output: yes
Overall yes
output
What software can Judy use?
?- can_use(judy, X).
This query demonstrates how backtracking is done to find all answers.
Rules or
Bindings of
Level Results of deduction facts to
variables
be applied
Original can_use(judy, X).
Rule 1 P = judy
query
Comp =
1 access(judy, Comp), can_run(Comp, X). Fact 11
comp1
2 can_run(comp1, X). Rule 2 -
spec(comp1, CompType, MemAvail),
CompType =
pc
3 runs(CompType, X, MemNeeded), Fact 1
MemAvail >= MemNeeded. MemAvail =
32
X=
runs(pc, X, MemNeeded), movie_edit
4 32 >= MemNeeded. Fact 4
MemNeeded =
96
5 32 >= 96. Failed! Backtracks.
X = vb
runs(pc, X, MemNeeded),
4 32 >= MemNeeded. Fact 5 MemNeeded =
16
32 >= 16. Satisfied!
5 X = vb is a solution to the original query. Output: X = vb
Backtracking is still peroformed because there may be other solutions. Then backtracks.
X = cpp
runs(pc, X, MemNeeded),
4 32 >= MemNeeded. Fact 6 MemNeeded =
28
5 32 >= 28. Satisfied!
Output: X = cpp
Then backtracks.
runs(pc, X, MemNeeded),
4 32 >= MemNeeded. Failed! Backtracks.
spec(comp1, CompType, MemAvail),
3 runs(CompType, X, MemNeeded), Failed! Backtracks.
MemAvail >= MemNeeded.
2 can_run(comp1, X). Failed! Backtracks.
1 access(judy, Comp), can_run(Comp, X). Failed! Backtracks.
Failed!
Original can_use(judy, X). Since the top level is
query reached, all answers are
found.
Overall x = vb
output x = cpp
Who can use MovieEdit?
?- can_use(X, movie_edit).
Backtracking has to be performed before concluding that there is no answer to a query.
Rules or
Bindings of
Level Results of deduction facts to
variables
be applied
Original can_use(X, movie_edit). SW =
Rule 1
query movie_edit
X = judy
1 access(X, Comp), can_run(Comp, movie_edit). Fact 9 Comp =
comp1
2 can_run(comp1, movie_edit). Rule 2 -
4
runs(pc, movie_edit, MemNeeded),
Fact 4 MemNeeded =
32 >= MemNeeded. 96
5 32 >= 96. Failed! Backtracks.
runs(pc, movie_edit, MemNeeded),
4 32 >=MemNeeded. Failed! Backtracks.
spec(comp1, CompType, MemAvail),
3 runs(CompType, movie_edit, MemNeeded), Failed! Backtracks.
MemAvail >= MemNeeded.
2 can_run(comp1, movie_edit). Failed! Backtracks.
X = peter
1 access(X, Comp), can_run(Comp, movie_edit). Fact 10 Comp =
comp3
2 can_run(comp3, movie_edit). Rule 2 -
spec(comp3, CompType, MemAvail),
CompType =
pc
3 runs(CompType, movie_edit, MemNeeded), Fact 3
MemAvail >= MemNeeded. MemAvail =
64
4
runs(pc, movie_edit, MemNeeded),
Fact 4 MemNeeded =
64 >= MemNeeded. 96
5 64 >= 96. Failed! Backtracks.
runs(pc, movie_edit, MemNeeded),
4 64 >=MemNeeded. Failed! Backtracks.
spec(comp3, CompType, MemAvail),
3 runs(CompType, movie_edit, MemNeeded), Failed! Backtracks.
MemAvail >= MemNeeded.
2 can_run(comp3, movie_edit). Failed! Backtracks.
X = david
1 access(X, Comp), can_run(Comp, movie_edit). Fact 11 Comp =
comp1
2 can_run(comp1, movie_edit). Rule 2 -
4
runs(pc, movie_edit, MemNeeded),
Fact 4 MemNeeded =
32 >= MemNeeded. 96
5 32 >= 96. Failed! Backtracks.
runs(pc, movie_edit, MemNeeded),
4 32 >=MemNeeded. Failed! Backtracks.
spec(comp1, CompType, MemAvail),
3 runs(CompType, movie_edit, MemNeeded), Failed! Backtracks.
MemAvail >= MemNeeded.
2 can_run(comp1, movie_edit). Failed! Backtracks.
X = david
1 access(X, Comp), can_run(Comp, movie_edit). Fact 12 Comp =
comp2
2 can_run(comp2, movie_edit). Rule 2 -
spec(comp2, CompType, MemAvail),
CompType =
mac
3 runs(CompType, movie_edit, MemNeeded), Fact 2
MemAvail >= MemNeeded. MemAvail =
128
runs(mac, movie_edit, MemNeeded),
4 128 >= MemNeeded. Failed! Backtracks.
spec(comp2, CompType, MemAvail),
3 runs(CompType, movie_edit, MemNeeded), Failed! Backtracks.
MemAvail >= MemNeeded.
2 can_run(comp2, movie_edit). Failed! Backtracks.
1 access(X, Comp), can_run(Comp, movie_edit). Failed! Backtracks.
Failed. The top level is
Original can_use(X, movie_edit). reached and no answers
query have been found.
Output: no
Overall no
output