2.4 Practical Session 2

By this stage, you should have had your first taste of running Prolog programs. The purpose of the second practical session is to suggest two sets of keyboard exercises which will help you get familiar with the way Prolog works. The first set has to do with matching , the second with proof search.

First of all, start up your Prolog interpreter. That is, get a screen displaying the usual `I'm ready to start' prompt, which probably looks something like:

?-

Now verify your answers to Exercise 1.1, the matching examples. You don't need to consult any knowledge bases, simply ask Prolog directly whether it is possible to unify the terms by using the built-in =/2 predicate. For example, to test whether food(bread,X) and food(Y,sausage) unify, just type in

food(bread,X) = food(Y,sausage).

and hit return.

You should also look at what happens when Prolog gets locked into an attempt to match terms that can't be matched because it doesn't carry out an occurs check. For example, see what happens when you give it the following query:

g(X,Y) = Y.

Ah yes! This is the perfect time to make sure you know how to abort a program that is running wild!

Well, once you've figured that out, it's time to move onto something new. There is another important built-in Prolog predicate for answering queries about matching, namely \=/2 (that is: a 2-place predicate \=). Roughly speaking, this works in the opposite way to the =/2 predicate: it succeeds when its two arguments do not unify. For example, the terms a and b do not unify, which explains the following dialogue:

a \= b
 
yes

Make sure you understand the way \=/2 predicate works by trying it out on (at least) the following examples. But do this actively, not passively. That is, after you type in an example, pause, and try to work out for yourself what Prolog is going to respond. Only then hit return to see if you are right.

  1. a \= a

  2. 'a' \= a

  3. A \= a

  4. f(a) \= a

  5. f(a) \= A

  6. f(A) \= f(a)

  7. g(a,B,c) \= g(A,b,C)

  8. g(a,b,c) \= g(A,C)

  9. f(X) \= X

Thus the \=/2 predicate is (essentially) the negation of the =/2 predicate: a query involving one of these predicates will be satisfied when the corresponding query involving the other is not, and vice versa (this is the first example we have seen of a Prolog mechanism for handling negation). But note that word `essentially'. Things don't work out quite that way, as you will realise if you think about the trickier examples you've just tried out...

It's time to move on and introduce one of the most helpful tools in Prolog: trace. This is an built-in Prolog predicate that changes the way Prolog runs: it forces Prolog to evaluate queries one step at a time, indicating what it is doing at each step. Prolog waits for you to press return before it moves to the next step, so that you can see exactly what is going on. It was really designed to be used as a debugging tool, but it's also really helpful when you're learning Prolog: stepping through programs using trace is an excellent way of learning how Prolog proof search works.

Let's look at an example. In the lecture, we looked at the proof search involved when we made the query k(X) to the following knowledge base:

f(a).
f(b).
 
g(a).
g(b).
 
h(b).
 
k(X) :- f(X),g(X),h(X).

Suppose this knowledge base is in a file proof.pl. We first consult it:

1 ?- [proof].
% proof compiled 0.00 sec, 1,524 bytes
 
yes

We then type `trace.' and hit return:

2 ?- trace.
 
Yes

Prolog is now in trace mode, and will evaluate all queries step by step. For example, if we pose the query k(X), and then hit return every time Prolog comes back with a ?, we obtain (something like) the following:

[trace] 2 ?- k(X).
   Call: (6) k(_G348) ?  
   Call: (7) f(_G348) ?  
   Exit: (7) f(a) ?  
   Call: (7) g(a) ?  
   Exit: (7) g(a) ?  
   Call: (7) h(a) ?  
   Fail: (7) h(a) ?  
   Fail: (7) g(a) ?  
   Redo: (7) f(_G348) ?  
   Exit: (7) f(b) ?  
   Call: (7) g(b) ?  
   Exit: (7) g(b) ?  
   Call: (7) h(b) ?  
   Exit: (7) h(b) ?  
   Exit: (6) k(b) ?  
 
X = b  
 
Yes

Study this carefully. That is, try doing the same thing yourself, and try to relate this output to the discussion of the example in the text. To get you started, we'll remark that the third line is where the variable in the query is (wrongly) instantiated to a, and that the line marked redo is when Prolog realizes it's taken the wrong path, and backtracks to instantiate the variable to b.

While learning Prolog, use trace, and use it heavily. It's a great way to learn.

Oh yes: you also need to know how to turn trace off. Simply type `notrace.' and hit return:

notrace.


Patrick Blackburn, Johan Bos and Kristina Striegnitz
Version 1.2.5 (20030212)