Session 1: Introduction to prolog and SWI-Prolog.

In this session we will introduce the basics of prolog: some elementary build-in predicates, adding and consulting facts from the database, consulting files and rules. Just like with all programming languages one has to select a specific engine. In this session we give an introduction to the engine we will use mostly in this course: SWI-prolog.

Getting started

With the exception of the exercise session on constraint logic programming, we will use SWI Prolog. This prolog edition is LGPL licenced and available for free from http://www.swi-prolog.org/. Pre-compiled versions for Unix, Windows and Apple as well as source code and documentation can be downloaded so you can install the software on your personal computer. On the computers in the PC-rooms at Campus Arenberg and at the LUDIT center SWI is already installed (version 5.2.13). Under Windows, you can start SWI by selecting Start - Programs - EXTERNAL - SWI Prolog (not SICStus Prolog 3.10.1). The prolog engine will then show up in a small text-based window looking (more or less) like the window below.

A prolog engine can be seen as a combination of a program language interpreter and a database program. Some very simple build-in predicates will illustrate the first aspect:

?- write(hello).
hello

Yes

At first we would say that the write predicate of prolog is comparable with e.g. the printf command in c/c++: it echos on the screen its parameter (in prolog we will call this the argument). But this view on 'write' does not explain the 'Yes' that is printed after 'hello'! This can only be explained when we see prolog as an engine for consulting and manipulation knowledge bases. The prolog prompt ('?-') is already an indication that we are asking questions to a system. In this view the above 'write' should be seen as asking the system "can you write the word 'hello' on the screen?". The system replies by doing so and afterwards says "Yes" (read: yes, I can do what you asked me). With what we know so far this can look stupid: we saw he was able to print the word 'hello' on the screen, why the explicit 'Yes'? We will see later on that we can ask prolog things for which we can't see from its response if it was able to do this or not; then the explicit 'Yes' comes in handy.

Did you get something different on your prolog prompt? Most likely you got this:

?- write(hello)
|

with the cursor blinking at line 2. The problem is you forgot the full stop ('.') at the end of the query. Prolog lets you type till you type a full stop followed by return. Only then Prolog starts inspecting and executing the query you asked it. So you can continue your query by just typing '.' followed by return:

?- write(hello)
|    .
hello

Yes

Another thing that can result in a different result is this:

?- write(Hello).
_G236

Hello = _G236 

Yes

(The letter and number after the '_' may differ). Every argument starting with a capital letter or an underscore is a variable in prolog. Internally the prolog interpreter uses a different name for the variables you use. In this case the internal representation of your variable Hello is _G236, which prolog prints, then it tells you that 'your' variable Hello and 'its' variable _G236 are one and the same (Hello = _G236) after which it concludes with 'Yes'.

Let's try a more complex query:

?- write(hello world).
ERROR: Syntax error: Operator expected
ERROR: write(hello 
ERROR: ** here **
ERROR: world) . 

What went wrong? In the first query we asked prolog not to print the string hello but to print the constant symbol hello. However, now we are talking about the constant symbol hello world but by convention (read: just remember and learn to live with it) constants in Prolog cannot have a space in it. If we want to define a string (notice that prolog has no explicit type definitions) we write single quotes around the string:

?- write('hello world').
hello world

Yes

The explicit indication that something is a string can also be used to solve the 'problem' we had with the variable Hello: if we write single quotes Prolog will know this is a string and not a variable:

?- write('Hello').
Hello

Yes

Another common mistake when dealing with strings is the use of double quotes instead of single quotes. Can you guess the meaning of the output?:

?- write("hello world").
[104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]

Yes
These numbers are the ASCII codes of the letters in the string (104 is h, 101 is e, ...).

Adding knowledge to the knowledge base

In the previous part we explained that prolog can be seen as a knowledge base which we can ask queries. We also explained that it comes with 'build-in knowledge' such as how to write text to the screen. Although this can be handy, we will need to provide the knowledge base information about the application at hand. Suppose we want to tell prolog the information available in this (imaginary) text:

Books have a unique ID, their ISBN code: e.g. the book 'The art of Prolog' (written by Statler, 400 pages) has ISBN code 1 and the book 'The mistery of strawberries' (by Waldorf, 42 pages) has ISBN 23. Furthermore, suppose Waldorf owns a copy of 'The mistery of strawberries' (but Statler doesn't). Neither Statler nor Waldorf own a copy of 'The art of Prolog' , Statler even hates this book.

If we want to represent this in a relational database we would create 5 tables: one to store information about books, one to store information about people, and three to represent the different relations between books and people (owns, author, hate).

book table
isbn title pages
1 the art of prolog 400
23 the mistery of strawberries 42

person table
name
statler
waldorf

owns table
person isbn
waldorf 23

author table
person isbn
statler 1
waldorf 23

hate table
person isbn
statler 1

If we want to enter this information into prolog, we write it as facts:

book(1,'The art of Prolog',400).
book(23,'The mistery of Strawberries',42).
person('Statler').
person('Waldorf').
author('Statler',1).
author('Waldorf',23).
hates('Statler',1).
owns('Waldorf',23).

But how do we enter this information into the engine? If we type it at the prompt, prolog complains:

?- book(1,'The art of Prolog',400).
ERROR: Undefined procedure: book/3

Prolog complains because we are asking it a query about books, but it never got information about books. In fact we don't want to ask Prolog about books, but we want to ask it "Can you add information about this book into your knowledge base?". For this we have to use a build-in predicate assert:

?- assert(book(1,'The Art of Prolog',400)).

Yes

Pay attention to the parentheses! We see that prolog says 'Yes', and thus was able to add the knowledge about this book to its database.

Querying the knowledge base

We can now start to ask prolog queries about books. We start with the query that gave an error a few minutes ago:
?- book(1,'The Art of Prolog',400).

Yes

Prolog doesn't complain anymore: it answers 'Yes, it is true, there is a book with isbnnr 1, title 'The Art of Prolog' which contains 400 pages'. If we ask it about the strawberry-book however, it replies 'No':

?- book(23,'The mistery of Strawberries',42).

No
This is because of one of the principles of prolog: the closed world assumption, which states that prolog only considers things to be true if it can prove that it is true, otherwise it will consider them false (where we humans would consider it 'unknown').

Variables are very important: if we use them in a query we are asking prolog: 'is there a value for this variable(s) such that the query is true'. Prolog will either answer with 'No' or by providing a value for the variable(s) for which the query succeeds. Remember that a variable in prolog starts with a capital letter (or an underscore). For example, consider the query

?- book(1,Title,Pages).

Title = 'The Art of Prolog'
Pages = 400 

We are asking 'are there values for the variables Title and Pages such that book(1,Title,Pages) is true', but a more common interpretation of this query is 'is there a book with isbnnr 1 and if so, give me the title and number of pages'. As with most programming languages the exact name of the variable is not important for prolog; we could have formulated the query also like this: ?- book(1,Absolute,Nonsense).

Notice that prolog does not answer 'Yes' nor 'No'. It doesn't show the query prompt (?-) either. This is because for prolog the query is not yet completely answered: prolog gave you one possible 'variable substitution' (answer) for which your query is true, but there may be more correct answers and prolog gives you the choice between checking for more answers or stop with this answer. If you want to see if there are other substitutions, you type a semicolon (';'). In this case prolog will respond with 'No', telling you "No, there are no more solutions". If on the other hand you pressed enter (or return), prolog would respond with 'Yes', telling you "Yes, I found an answer for the query you asked me".

Adding knowledge, part 2

Up till now we only added one fact to our knowledge base. Try to enter the rest of the knowledge (about books, authors, ,...) via the assert predicate. This requires some effort, especially because you always have to repeat the word 'assert()'. But what is even worse is that if you quit prolog, all knowledge you entered in the system is lost, and you would need to type everything again in a later session!

Of course there is a solution to this: the consult predicate. Just like assert allows you to enter one fact or rule into the knowledge base, consult will add all facts and rules that are defined in a specified file into the knowledge base. The file that prolog consults is just a plain text file, so you can create it with whatever text editor you like: many people are used to notepad, ... and if you want to use those, please do so, but keep in mind to save your file in plain ascii (so no .doc or .rtf files) and make sure you save them with extension .pl (e.g. notepad always adds the extension .txt, so be careful when using notepad). SWI prolog comes with a build-in editor that is a downgrade of the popular emacs editor. We briefly introduce this editor below. Note that this information about the editor is just meant to help you work with prolog. You do not need to know it for the exam. More information about the editor can be found in the SWI prolog manual.

To start the editor just use the build-in predicate emacs: ?- emacs. and press enter. After a few seconds a new window with the editor appears. Note that, while the new window is open, the emacs query succeeded and you get a new prolog query prompt (?-). Emacs by default always opens his 'scratch' window, where you can take notes you don't want to save. We don't want to scratch but want to do serious work, so we open a new file: click 'File' and then 'Find file...' and then we type as file name 'D:\user\books.pl' and click OK. Now we can start typing the facts about our books and authors. After you typed all the information your emacs window should look like this:

Notice the coloring (predicate name in bold red, strings in blue, indication of matching parentheses,...) that happens after you finished typing a clause (by typing '.'). Now save this file (File -> save buffer). Keep in mind that our prolog engine still hasn't received the 'knowledge' about books and authors: we created a file but prolog did not yet consult that file. So let's do this now:

?- consult('d:/user/books.pl').
Warning: (d:/user/books.pl:1):
        Redefined static procedure book/3
% books.pl compiled 0.01 sec, 1,004 bytes

Yes

Prolog gives us a warning. Usually you will not provide the same predicates (in this case book) with assert and consult, that is why prolog gives us a warning. When you close down prolog and start it up later on and then do the consult, you will see everything goes as planned, without warning.

Rules

To provide Prolog with knowledge we can not only provide facts, but also rules. Suppose we want to call each book that contains less than 100 pages a brochure. We could do this manually by watching all facts and as soon as we see a book/3 fact with that book having less than 100 pages we introduce a brochure/1 fact for this book. But of course we want to automate this and let the computer do all the work. To do so, we should be able to provide the definition of a brochure to prolog and let prolog do the checking. This is where rules come into play!

brochure(ISBN):-
    book(ISBN,_,Pages),
    Pages < 100.

The above rule defines a brochure as a predicate with 1 argument. Each time prolog uses this predicate it 'substitutes' the predicate with this conjunction (see the Bratko book for execution traces). Add this rule to your file books.pl, save it and consult it. Test it with the query ?- brochure(Broch).

Exercises

  1. Formulate a query to retrieve ISBN numbers.
  2. Formulate a query to retrieve the names of books that are hated by their author.
  3. Formulate a query to retrieve the names of the books together with their author. Make prolog print for each result a line like this:
    the book booktitle is written by author name
  4. Write a predicate proud_author/1 which succeeds for all people that own at least one of the books they have written.
  5. With what you know so far, is it possible to write a predicate that returns the number of books in the knowledge base?
    (No! Using your current knowledge this is not possible! Can you explain why this is the case?)
  6. How would you represent knowledge of libraries having copies of certain books? Try to think of multiple representations, discuss pros and cons. Implement the best representation and test it on some queries.
  7. Create a knowledge base that 'translates' each build-in predicate introduced in this session into another language than English (e.g. your native language). Test these predicates. For Dutch, for instance, you should be able to ask queries such as ?- schrijf('Hoi'), nieuwelijn, stop..

Getting stopped

You solved all exercises or the session has finished? Then you can use the halt predicate to exit the prolog engine (this is the most clean way to exit SWI-Prolog):

?- halt.