# Prolog ("PROgrammation en LOGique")

Thinking as Computation, 3, 4, Appendix A, Appendix B, Appendix C, Appendix D

(Hector Levesque (author of CT) has made available a collection of prolog programs. I recommend that you download them. This will make it easier to work with some of the examples in the book.)

Prolog is a computer language based on logic programming.

For a straightforward and helpful general tutorial on Prolog, see Learn Prolog Now!

In Prolog, programs are definite programs. The way Prolog works will be partly familiar to you on the basis of the last lecture. On the left below, there are two examples of clauses in the propositional calculus. On the right, there are the corresponding ways they are written in Prolog.

```
a               |               a.                      (fact)
|
a ∨ ¬b ∨ ¬c     |               a :- b, c.              (rule) (head :- body)

```

The following set of equivalences helps to clarify the correspondence:

```
a ∨ ¬b ∨ ¬c      iff           a ∨ ¬(b ∧ c)
(b ∧ c) → a
a ← (b ∧ c)
a :- b, c.

```

Queries are understood as negative clauses. The following is a negative clause:

¬a ∨ ¬b ∨ ¬c

This negative clause is equivalent to

¬(a ∧ b ∧ c)

In Prolog, this negative clause corresponds to a query and is written as

?- a, b, c.

The basic evaluation step of Prolog is the backward chaining process in logic programming.

(This corresponds to an application of the inference rule called resolution. Given two clauses presented in disjunctive format, resolution eliminates a pair of complementary literals and constructs a new clause (the resolvent) from the literals that remain. Two literals are complimentary if and only if one is the negation of the other.)

```
In Prolog                               In logic

query           ?-a,d,e.                ¬a ∨ ¬d  ∨ ¬e
program clause  a:-b,c.                  a ∨ ¬b ∨ ¬c
derived query   ?-b,c,d,e.              ¬b ∨ ¬c  ∨ ¬d ∨ ¬e

```

The logical relationship is {query, program clause} ⊢ derived query

Here are some screen shots from a session some years ago. I was playing around with a simple KB.

This is how my screen looks when I started Prolog:

```Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 6.6.1)
Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.

For help, use ?- help(Topic). or ?- apropos(Word).

1 ?-

```

Here is how it looks when I entered (or asserted) some facts and rules into the KB. (For some explanation of the four database manipulation commands in Prolog, see Database Manipulation in the tutorial.) The fact that I assert is "Socrates is a man." The rule that I assert is "whatever is a man is mortal":

```
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 6.6.1)
Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.

For help, use ?- help(Topic). or ?- apropos(Word).

1 ?- assert(man(socrates)).
true.

2 ?- assert( (mortal(X):-man(X)) ).
true.

3 ?-

```

Here is how it looked when I gave Prolog certain goals. I asked "whether Socrates is a man," "whether something is mortal," and "whether something is man":

```
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 6.6.1)
Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.

For help, use ?- help(Topic). or ?- apropos(Word).

1 ?- assert(man(socrates)).
true.

2 ?- assert(mortal(X):-man(X)).
true.

3 ?- man(socrates).
true.

4 ?- mortal(X).
X = socrates.

5 ?- man(X).
X = socrates.

6 ?-
```

• The "Family" example (CT, 42).

Here is a listing of the facts and rules:

```
% This is the Prolog version of the family example

child(john,sue).   child(john,sam).
child(jane,sue).   child(jane,sam).
child(sue,george).   child(sue,gina).

male(john).   male(sam).     male(george).
female(sue).  female(jane).  female(june).

parent(Y,X) :- child(X,Y).
father(Y,X) :- child(X,Y), male(Y).
opp_sex(X,Y) :- male(X), female(Y).
opp_sex(Y,X) :- male(X), female(Y).
grand_father(X,Z) :- father(X,Y), parent(Y,Z).

```

Here is a session in which I asked some questions:

```
% p:/Work Desktop/family.pl compiled 0.02 sec, 18 clauses
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 6.6.1)
Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.

For help, use ?- help(Topic). or ?- apropos(Word).

1 ?- father(sue,X).
false.

2 ?- father(sam,X),female(X).
X = jane.

3 ?- child(X,sam).
X = john ;
X = jane.

4 ?- male(president_crow).
false.

5 ?-

```

• To test your understanding, here is a question about the fourth query in the family example.

President Crow (of ASU) is male, but Prolog responds with "false" to the question of whether President Crow is male (?- male(president_crow)). What is going on here? To answer, explain what "false" means in this context. It cannot very well mean that the statement "President Crow is male" is false. Presumably, then, it means that something else is false. What is it?

• Here is how the Pulp Fiction example looks in Prolog on my Arch Linux machine. (This machine is newer than the one I used in the previous examples, so this example looks a little different). I consult a file I created called "pulpfiction." This file contains the program. I list the two predicates. I ask a few questions. I halt Prolog.

```
tom:arch [~]
% swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.2.3)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.

For help, use ?- help(Topic). or ?- apropos(Word).

?- [pulpfiction].
true.

?- listing(loves).
loves(vincent, mia).
loves(marcellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).

true.

?- listing(jealous).
jealous(A, B) :-
loves(A, C),
loves(B, C).

true.

?- loves(mia,vincent).
false.

?- jealous(marcellus, W).
W = vincent .

?- halt.

tom:arch [~]
%

```

• This is not a course in computer programming, but you should play around some with Prolog.

One way to play with Prolog is to use the online version, in which you can cut and paste programs and queries.

Another way to play with Prolog is install it on your computer. This is what I have done. To start Prolog, I open a command terminal and issue the command "swipl":

```
tom:arch [~]
% swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.3)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

For built-in help, use ?- help(Topic). or ?- apropos(Word).

?-
```

At that point, Prolog waits for a goal. (The "?-" its way of asking for a goal.) To play around, I gave it the goal of writing "Hello master." I did this by giving it a conjunction of goals:

```
?- write('Hello '), write('master.').
Hello master.
true.

?-
```

The way Prolog uses variables is potentially confusing. To get some insight into how this works, first put the following in a file (example.pl) for Prolog to consult:

greet(tom) :- write('Hello '), write('master.').
greet(teacher) :- write('Hello '), write('master.').
greet(Name) :- write('Hello '), write(Name).

```
?- consult('example.pl').
true.

?- listing(greet).
greet(tom) :-
write('Hello '),
write('master.').
greet(teacher) :-
write('Hello '),
write('master.').
greet(A) :-
write('Hello '),
write(A).

true.

?-

```

"Name" is a variable. (Prolog treats any term that begins with an uppercase letter (or the underscore) as a variable.) When I give Prolog the goal "greet(name)," it unifies the constant "name" with the variable "Name" in the third rule in the KB. (The variable is bound to the constant.) The goal, in this way, has been reduced to the conjunction "write('Hello '), write(name)."

```
?- greet(name).
Hello name
true.

```

Variables can appear in goals. When I give Prolog the goal "greet(Person)," it unifies the variable "Person" with the constant "tom" in the first rule of the KB. Because the variable was in the supplied goal, Prolog identifies the constant to which the variable was bound:

```
?- greet(Person).
Hello master.
Person = tom .

?-
```

Prolog can disregard the current binding and look for another. This is what happens when I type ";" (which is logically equivalent to "or"):

```
?- greet(Person).
Hello master.
Person = tom ;
Hello master.
Person = teacher .

?-
```

For a slightly more complicated example, consider again the blocks program from the previous lecture:

```
on(b1,b2).
on(b3,b4).
on(b4,b5).
on(b5,b6).

above(X,Y) :- on(X,Y).
above(X,Y) :- on(X,Z), above(Z,Y).
```

This program consists in four facts (about which block is on top of which block) and two rules (that define the "above" relation). Corresponding to the facts and rules is the following model of the world (use your imagination to see blocks on top of one another):

```
b3
b4
b1     b5
b2     b6

```

As expected, Prolog solves "above(b3,b5)" and "above(X,Y)."

```
?- consult('block.pl').
true.

?- above(b3,b5).
true.

?- above(X,Y).
X = b1,
Y = b2 ;
X = b3,
Y = b4 ;
X = b4,
Y = b5 ;
X = b5,
Y = b6 ;
X = b3,
Y = b5 ;
X = b3,
Y = b6 ;
X = b4,
Y = b6 ;
false.

```

Here is the trace for "above(b3, b5)." I have added some explanation.

```
?- trace.
true.

```

(creep causes the debugger to single-step. leap causes it to resume running the program. You probably thought computer scientists have no sense of humor.)

The query "above(b3, b5)" unifies with the first rule. The derived query is "on(b3, b5)." This derived query fails.

```
[trace]  ?- above(b3,b5).
Call: (8) above(b3, b5) ? creep
Call: (9) on(b3, b5) ? creep
Fail: (9) on(b3, b5) ? creep

```

Now we have to try the query with the second rule.
The second rule now takes the form "above(b3, b5) :- on(b3, _8972), above(_8972, b5)."
"_8972" is a variable. It is bound to "b4."
The derived query list is "on(b3, b4), above(b4, b5)."
These queries succeed, so the original query succeeds.

```
Redo: (8) above(b3, b5) ? creep
Call: (9) on(b3, _8972) ? creep
Exit: (9) on(b3, b4) ? creep
Call: (9) above(b4, b5) ? creep
Call: (10) on(b4, b5) ? creep
Exit: (10) on(b4, b5) ? creep
Exit: (9) above(b4, b5) ? creep
Exit: (8) above(b3, b5) ? creep
true .

```

Here is the trace for "above(Block, b5)."
Prolog gives the query the form "above(_8790, b5)." This unifies with the first rule. The variable is bound to "b4."
The derived query succeeds, so the original query succeeds.

```
[trace]  ?- above(Block,b5).
Call: (8) above(_8790, b5) ? creep
Call: (9) on(_8790, b5) ? creep
Exit: (9) on(b4, b5) ? creep
Exit: (8) above(b4, b5) ? creep
Block = b4 .

```

To see an example in which Prolog discards a binding and looks for another, I gave Prolog the goal "above(b3,b3)."
I inserted some explanation here too.

```
[trace]  ?- above(b3,b3).
```

The query is unified with the first rule. This fails because "on(b3, b3)" fails.

```
Call: (8) above(b3, b3) ? creep
Call: (9) on(b3, b3) ? creep
Fail: (9) on(b3, b3) ? creep
```

So we have to try the query again. This time we try it with the second rule.
The second rule now takes the form "above(b3, b3) :- on(b3, _6374), above(_6374, b3)."
"_6374" is a variable. It is bound to "b4."
The derived query list is "on(b3, b4), above(b4, b3)." The first query in the list succeeds, but the second query in the list fails against the first rule because "on(b4, b3)" fails.

```
Redo: (8) above(b3, b3) ? creep
Call: (9) on(b3, _6374) ? creep
Exit: (9) on(b3, b4) ? creep
Call: (9) above(b4, b3) ? creep
Call: (10) on(b4, b3) ? creep
Fail: (10) on(b4, b3) ? creep
```

So now we try the query "above(b4, b3)" with the second rule. This time the variable is bound to "b5." The derived query list is "on(b4, b5), above(b5, b3)." The first query in this list succeeds, but the second fails against the first rule because "on(b5, b3)" fails.

```
Redo: (9) above(b4, b3) ? creep
Call: (10) on(b4, _6374) ? creep
Exit: (10) on(b4, b5) ? creep
Call: (10) above(b5, b3) ? creep
Call: (11) on(b5, b3) ? creep
Fail: (11) on(b5, b3) ? creep
```

So now we try the query "above(b5, b3)" with the second rule. This time the variable is bound to "b6." Now the derived query list is "on(b5, b6), above(b6, b3)." The first query in this list succeeds, but the second fails against the first rule because "on(b6, b3)" fails.

```
Redo: (10) above(b5, b3) ? creep
Call: (11) on(b5, _6374) ? creep
Exit: (11) on(b5, b6) ? creep
Call: (11) above(b6, b3) ? creep
Call: (12) on(b6, b3) ? creep
Fail: (12) on(b6, b3) ? creep
```

Now there is no constant to bind to the variable. All the attempts have failed, so the query "above(b3, b3)" fails.

```
Redo: (11) above(b6, b3) ? creep
Call: (12) on(b6, _6374) ? creep
Fail: (12) on(b6, _6374) ? creep
Fail: (11) above(b6, b3) ? creep
Fail: (10) above(b5, b3) ? creep
Fail: (9) above(b4, b3) ? creep
Fail: (8) above(b3, b3) ? creep
false.

[trace]  ?-

```

Some Explanation of Lists in Prolog

We will uses lists in Prolog later in the course when we come to natural language processing (NLP).

Lists are a finite sequence of elements. They are specified in Prolog by separating the elements by commas and enclosing them in square brackets. The empty list is a list.

A non-empty list has a head and a tail. The head is the first element. The tail is the rest. Prolog has a built-in operator | to decompose a list into its head and tail.

```
tom:arch [~]
% swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.3)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

For built-in help, use ?- help(Topic). or ?- apropos(Word).

false.

?- [Head|Tail]  =  [mia,  vincent,  jules,  yolanda].
Tail = [vincent, jules, yolanda].

?-

```

An Adventure Game Written in Prolog

Here is the game. I found it on the internet.
I have not played it enough to know how well it works. (I am not much into computer games.)
You might find it interesting to play it and to look at the program to see why it does what it does.

```
% swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.3)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- consult('spider.pl').
true.

?- start.

Enter commands using standard Prolog syntax.
Available commands are:
start.                   -- to start the game.
n.  s.  e.  w.  u.  d.   -- to go in that direction.
take(Object).            -- to pick up an object.
drop(Object).            -- to put down an object.
kill.                    -- to attack an enemy.
look.                    -- to look around you again.
instructions.            -- to see this message again.
halt.                    -- to end the game and quit.

You are in a meadow.  To the north is the dark mouth
of a cave; to the south is a small building.  Your
assignment, should you decide to accept it, is to
recover the famed Bar-Abzad ruby and return it to

true.

?-

```