Introduction to Prolog


Reference Materials

Chapter 5 of our text introduces programming in Prolog (although not in a very complete manner).

A very (very) basic summary of Prolog syntax can be found courtesy of Dr. Ralph Morelli at Trinity College.

A very nice intermediate introduction to prolog, in the form of lecture notes, is provided by Ulle Endriss of Universiteit van Amsterdam.

A wonderful Prolog tutorial, with more in-depth exercises and examples on which we will rely, is found courtesy of Dr. John Fisher at CalState Pomona

If you want to challenge yourself, check out the following Ninety-Nine Prolog Problems (with solutions embedded).


Technical Support

We will be relying on the SWI-Prolog implementation. (As an aside, there will be a Boot Camp in SWI-Prolog happening as a preconference workshop on September 18th, as part of this year's StrangeLoop conference in UCity.)

SWI-Prolog is installed on turing (as an executable swipl), and it is freely available for all computing platforms. We recommend that you use SWI-PL for consistency with this course, since not all Prolog implementations use precisely the same commands.

Prolog source code is typically saved in a file using the .pl extension (although some use .pro). You can use your favorite editor, or there is a GUI IDE included with SWI-Prolog that can be invoked from the Prolog shell as prolog_ide.

tracing/debuging There is also advanced support for tracing and debugging prolog programs, that will be very instructive in demonstrating the effective flow of control of the program. This can be done by executing the command trace. at the prolog query prompt, and if you first execute guitracer, you will get the graphical version of a trace (rather than the default terminal output). For maximum info, we suggest the following combination:

guitracer.
visible(+all).
trace.

Facts and Rules (see below), are typically saved in advanced within a .pl file. For example, assume we have a file likes.pl that contains some definitions. That script can be executed from the command line using the command

swipl -s likes.pl
Otherwise, you can start up the swipl program, and then load the script using a command
[likes].
within the interpreter, in which case it will look for a file likes.pl in the working directory. You may also explicitly give the full file name within single quotes, as
['likes.pl'].
That is sometimes necessary if the filename has unusual characters, such as underscores.


Facts, Rules, and Goals

As our first example, we define a two-parameter predicate likes, such that likes(A,B) designates that A likes B.

We might populate a world with the following facts, stored in a file friends.pl (This file is also provided within turing:/Public/goldwasser/362/prolog):

likes(ross,rachel).
likes(rachel,ross).
likes(gunther,rachel).
likes(janice,joey).
likes(janice,chandler).
likes(chandler,monica).
likes(monica,chandler).
likes(ross,charlie).
likes(joey,charlie).
likes(joey,rachel).
likes(rachel,joey).
likes(charlie,ross).

Note that constants and predicates must start with a lowercase letter in Prolog.

We can then execute simple queries, such as:

?- likes(rachel,ross).
true .
?- likes(rachel,gunther).
false.

We may also use a variable, which must start with an uppercase letter in Prolog, as part of a query, as follows.

?- likes(X,rachel).
X = ross ;
X = gunther ;
X = joey.
Prolog attempts to unify the variable X in a way that makes the query true. Furthermore, it uses backtracking to try to find all possible solutions. If you try this, it will present you with the first solution and then pause. If you press space (or ;), it will present you with another, and so on. However if you enter a period (.) after seeing a solution, it ends the query without showing you any further solutions.

You may use multiple variables, and express a conjunction of several facts by giving a comma-separated set of goals. For example, we can query for pairs of people who like each other, as:

?- likes(X,Y), likes(Y,X).
X = ross,
Y = rachel ;
X = rachel,
Y = ross ;
X = chandler,
Y = monica ;
X = monica,
Y = chandler ;
X = ross,
Y = charlie ;
X = joey,
Y = rachel ;
X = rachel,
Y = joey ;
X = charlie,
Y = ross.
Note well that each pair of compatible couples is listed twice as a solution, due to the symmetry of X and Y (e.g, X=ross, Y=rachel, as well as Y=rachel, X=ross).

We can create new predicates that depend on this one by defining one or more rules. For example, we can define a compatible predicate adding the following rule.

compatible(X,Y) :- likes(X,Y),likes(Y,X).
This is really Prolog's syntax for a Horn clause, with compatible(X,Y) being the head of the clause. In PL1 syntax, we have stated that
∀X ∀Y likes(X,Y) ∧ likes(Y,X) ⇒ compatible(X,Y)
Here is another example of a predicate:
is_liked(Y) :- likes(X,Y).
This is equivalent to the PL1 statement
∀Y (∃X likes(X,Y)) ⇒ is_liked(Y)


Case Study: Family Relationships

To develop more complex rules, we will use a knowledge base involving parents and children. To allow for some interesting relationships such as half-siblings, I decided why not look to Hollywood. I've created a knowledge base hollywood.pl (available on turing) that includes portions of the family tree for the extended Sheen family (Martin, Charlie, ...) and the Douglas family (Kirk, Michael).

It includes three types of base predicates, including:

male(michael_douglas);
male(kirk_douglas);
parent_of(kirk_douglas, michael_douglas).
female(catherine_zeta_jones).
parent_of(catherine_zeta_jones, dylan_douglas).
...

We will work together to define various new predicates based on this. Interesting relationships might include:

mother_of(A,B)
father_of(A,B)
grandparent_of(A,B)
siblings(A,B)
halfsiblings(A,B)
cousins(A,B)
descendant_of(A,B)
related(A,B)


More Detailed Summary of Prolog Syntax/Semantics


Michael Goldwasser
Last modified: Monday, 30 September 2013