prologsystem to run Prolog programs
prologerror messages and repairing errors
This lab will create a number of files. If
you don't want them to go directly in your home directory, then create a
new directory and
cd to the new directory. For example:
% mkdir ai_lab % cd ai_lab
NOTE! Whenever we show you an example session on the computer,
what the system types to you will be in "
this font", and what
you are supposed to type in response will be in "
You do not need to type the percent sign (
at the start of these lines. In this situation, the percent sign represents
the Unix shell prompt. (It can also mark the start of a "comment", inside
a Prolog program.)
The first command created a directory called
ai_lab, the second command
ai_lab your current directory. Next time you log in you will not need
to create the directory... so just change directories using the command,
Prolog. We will start Prolog, directly enter some facts and queries, then quit.
prolog using the following command:
% prolog Welcome to SWI-Prolog (Multi-threaded, Version 5.6.58) or later Copyright (c) 1990-2008 University of Amsterdam. SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Please visit http://www.swi-prolog.org for details. For help, use ?- help(Topic). or ?- apropos(Word). ?-The
?-is the Prolog prompt. It indicates Prolog is ready to accept input from the keyboard.
NOTE! If at any time you make a mistake and you want to get a fresh
Prolog prompt, you can send the interupt signal, control-C,
a for abort.
To exit from Prolog, type control-D at a
prompt. You may have to read the previous note to find out how
to get a prompt.
?- control-D % halt
When we quit Prolog, (by typing control-D at a
the facts we have placed into memory are lost.
WARNING to Windows/DOS users! You should not try to quit
prolog using control-Z.
On the Unix systems, this will suspend the Prolog process
and leave it in the background. It does not quit the program!
(However, this may be different on systems using DOS or Microsoft Windows.)
c. We will record information on their colour. There are several ways to get this information into Prolog. I shall describe one way for the moment: preloading the data from a file that you had previously created, using the -s "switch" on the prolog command.
Create a file with the fact(s) you want to load into Prolog
in it, using your favourite text editor (like
Let's assume you call your file data1 and that it has
colour(a, red) in it:
% cat data1 colour(a, red).
We now start Prolog using the following form the the Unix prolog command:
% prolog -s data1 % data1 compiled 0.00 sec, 2,164 bytes ... followed by usual welcome message ... ?-
% starts a message from Prolog about the
processing of the file
Prolog now stores the fact that is in
in its memory (often called its database in this context).
The fact that you entered is
supposed to indicate that block
a is red.
The full stop (
.) at the end of each line of the file
indicates to Prolog that this is the end of a fact
If you leave out the full stop, Prolog will become confused.
It will issue an error message something like the following
ERROR: /import/.../yourlogin/data1:1: Syntax error: Unexpected end of file % data1 compiled 0.00 sec, 2,356 bytes
If this happens, type control-D to exit Prolog, and
have a look at your
emacs or whatever. Find the mistake, and fix it.
Then start Prolog again, with
prolog -s data1
ais red by asking the following query.
?- colour(a, red). true.Prolog attempted to prove this goal by checking its memory.
The reason Prolog can prove
a is red is that
we asserted that fact in the previous step. We can ask if
Prolog can prove that block
b is blue.
?- colour(b, blue). false.
It cannot prove it as we have not told Prolog this fact. We now exit
Prolog (by typing a control-D), and add a line with
colour(b, blue). on it
to the file
data1. Then we restart Prolog:
% prolog -s data1 ... messages and welcome ... ?- colour(a, red). true. ?- colour(b, blue). true.Now Prolog can prove that block
We will assume that block
c is painted half red and half blue.
That is, it is both red and blue. For this we need to add two facts
colour(c, red). colour(c, blue).Quit Prolog, edit
data1, restart Prolog, and use the following queries to test this.
?- colour(c, red). ?- colour(c, blue).
a, we can use the query...
?- colour(a, X).
X, is a variable. The name of a variable must
begin with a capital letter or an underscore character, "_".
Prolog responds by finding a posible value for
the goal can be proven.
X = red
After finding this binding, Prolog waits for the user to
type either a <return> or a semicolon (;). If the
user types a <return>, Prolog stops looking for bindings
that make the query provable, and says
true.. If the user
types a semicolon, Prolog looks for more bindings, and if it can't
find any, as here, responds
false.. Try it one way, then
repeat the query and try it the other way.
?- colour(Block, red). Block = a ; Block = c ; false.
Remember - you have to type the semicolons.
Here the goal can be proven for two different values of
false." just as before. Try this to find the colour of block
?- colour(d, X).
family.pl. Take a copy of the
% cp /home/cs9414/public_html/Labs/family.pl family.pl
more). The file shows a list of facts which represent a family tree. For your own benefit, you should draw a diagram of the family tree represented in the program and annotate each node with gender and date-of-birth information.
family.plprogram. (From now on we'll leave out Prolog's welcome message completely.):
% prolog -s family.pl ?-
Remember, if you make a mistake and you want to get a fresh Prolog prompt
:), you can send the interupt signal, control-C,
and then typing
a for abort.
You can quit SWI
prolog by sending the end-of-file signal,
control-D, at the prompt.
Prologwill read in the
family.plprogram and prompt you for input. Ask Prolog if Albert is the parent of Peter by entering the query:
?- parent(albert, peter).
true.to indicate that the goal was proven (as it was contained in the
?- parent(albert, brian).SWI
false.to indicate that the goal could not be proven from the
|and will then wait until some more stuff is entered. Try this now:
?- parent(albert, jim)SWI
prologwill just respond with...
|...until you enter the full-stop ...
| . true.
?- parent(X, brian).Here, X, is a variable which stands for an object which the questioner does not know about yet. Remember, the name of a variable must begin with a capital letter or an underscore character, "_".
Prolog replies with:
X = jim ; X = pat ; false.This is a listing of all values of
Xwhere the goal can be proven.
?- parent(x, brian).
This is an occasional source of errors in submitted assignments :-(
?- parent(albert, Brian). Brian = jim ; Brian = peter ; false.Here,
Brianis a variable and there are two solutions to the query. Work out (in your head, or on paper) what Prolog should respond with when given the query:
?- parent(Albert, Brian).then run the query to check your answer.
_, can be used when the value of the variable is not important. Values bound to the variable are not printed, and different appearances of
_are treated as separate variables. Try the following.
Is Albert a parent...
?- parent(albert, _).Who are the parents...?- parent(Parent, _).What does this one mean??- parent(_, _).
_variable is treated as a distinct variable. Try the query
?- parent(irene, _), parent(_, brian).Press the "
;" key each time Prolog stops after printing a response. You should see 4
trueresponses and then
false. This means that Prolog has found four ways to satisfy the query, because the two
_variables are treated as distinct. No variable bindings are printed because bindings of
_variables are not reported by Prolog. Thus the query above is similar to:
?- parent(irene, X), parent(Y, brian).which gives 4 solutions (try it) - except that the bindings are reported in this
Yversion of the query.
If we had instead done the query
?- parent(irene, X), parent(X, brian).we would get a single answer:
X = jim ; false.
?- parent(pat, X), parent(pat, Y), X \= Y. ?- X \= Y, parent(pat, X), parent(pat, Y).One of them succeeds but not the other. There are too many possible values of X and Y for which X is not equal to Y. Earlier versions of Prolog would get stuck in an infinite loop testing all the options. The current version of SWI-Prolog avoids the infinite loop, but in doing so it refuses to process the query and therefore fails to find any answer.
?- parent(irene, P), parent(P, brian).
P, represents that "someone" who is Brian's
parent and Irene's child.
Prolog will show all values for
P, where the query is true.
?- parent(irene, Child), parent(Child, GrandChild). Child = jim GrandChild = brian Child = peter GrandChild = lee Child = peter GrandChild = sandra Child = peter GrandChild = james Child = peter GrandChild = kate Child = peter GrandChild = kyleThe response shows there are six sets of values where the query is true. The six grandchildren are Brian, Lee, Sandra, James, Kate and Kyle.
One person, Grandparent, is the grandparent of another person, Grandchild, if: Grandparent is the parent of Child, and Child is the parent of Grandchild.
In Prolog this rule is written as:
grandparent(Grandparent, Grandchild) :- parent(Grandparent, Child), parent(Child, Grandchild).
Use your preferred text editor in another window
to append the rule
family.pl file. Don't forget to save your changes.
Prolog read the modified
consult command will force Prolog to re-read the
family.pl file; it automatically supplies the ".pl".
Prolog will now be aware of the changes you have made to the file,
and in fact it issues warnings for each Prolog procedure that you have
redefined by consulting "family.pl", just to sure you know which
procedures (may) have changed.
?- grandparent(irene, Who).Use the family tree you drew to confirm the result. If the result is not what you expected, then check your program for typing mistakes.
?- grandparent(Who, jenny).
% older(Person1, Person2) :- Person1 is older than Person2 % older(Person1, Person2) :- yearOfBirth(Person1, Year1), yearOfBirth(Person2, Year2), Year2 > Year1.
The first two lines are comments which serve as documentation for the new rule.
Also note the use of the built-in predicate ">".
older, tests whether one person is older than another. Test this new rule by asking who is older than Pat and then who is younger than Darren.
family.plprogram, add a rule,
siblings(Child1, Child2), to return whether two people are brothers or sisters (i.e. they share a common parent). Then add a rule,
olderBrother(Brother, Person), to return whether Brother is an older brother of Person.
?- siblings(sandra, X). X = lee ; X = james ; X = kate ; X = kyle ; false. ?- olderBrother(Brother, sandra). Brother = james ; false.
siblings does not report Sandra being her own
sibling. You may need to read the text book (Bratko) to find out how
to do this. The issue deals with equality (or inequality) of two terms.
Prolog has several notions of equality which are covered in the text book.
How does your program work when siblings share more than one parent? For example:
?- siblings(jim, X).
Why does this happen? You should be able to explain the reason for this perhaps unexpected result at some point, but you do not need to solve it at this stage.
parentrelation. We could then repeatedly find all the descendants of the descendants and so on. In Prolog this is done using recursion.
We will now add a recursive definition for the rule
descendant(Person, Descendant) which
when Descendant is a direct or indirect descendant of Person. First the base case:
descendant(Person, Descendant) :- parent(Person, Descendant).How would you phrase this rule in English?
Here is the recursive case:
descendant(Person, Descendant) :- parent(Person, Child), descendant(Child, Descendant).Add the
descendantpredicate to the
family.plprogram and re-consult.
?- descendant(Ancestor, kyle).However, as an exercise, write a predicate,
ancestor(Person, Ancestor), to do the same thing without using
descendant. The predicate
ancestorshould use only the
parentpredicate and recursion.
ancestor(Person, Ancestor)gives the same results as
Structures in Prolog are objects that have several components, but are treated as a single object. To combine the components into a single structure, we choose a functor and use it to group the components together. (See also Bratko, section 2.1.3. and section 2.2)
The following rule,
test, takes two arguments. The first
is a stucture with three components using functor,
The rule succeeds if (1) the first and second component of the structure
are the same, and (2) the last component of the structure is the same
as the last argument.
test(f(A, B, C), D) :- A = B, C = D.
Enter the rule into a file called, say,
test.pl, start up
Prolog with prolog -s test.pl and try
the following queries. Before each query write down what you
expect the resultss to be, then try it. If your expectations
fail, you should try to understand what is happening.
(See also Bratko, section 2.2)
?- test(f(1, 1, 2), 2). ?- test(f(1, 2, 3), 3). ?- test(f(1, 1, 2), 3). ?- test(f(1, X, 2), 2). ?- test(f(1, _, _), 2). ?- test(f(1, X, 2), Y). ?- test(g(1, X, 2), Y). ?- test(f(X, 1, Y, 1), 1). ?- test(f(X, 1, Y, 1)). ?- test(f(X, Y, Z), A). ?- test(f(X, Y), A). ?- test(X, a).
Use your text editor to create a new file,
add the following facts to the file.
% male(Person) % female(Person) % % The argument term for these predicates is a structure % representing a person. It is in the form: % person(FirstName, LastName) % male(person('Barry', 'Drake')). male(person('Jim', 'Fried')). female(person('Dot', 'Kanga')). % climb(Name, Grade, FirstAscentPerson, FirstAscentDate). % % This predicate records the climb details. % climb('Happy Go Lucky', 15, person('Barry', 'Drake'), date(11, 9,1996)). climb('High n Dry', 16, person('Jim', 'Fried'), date(11, 9,1996)). climb('Roller', 21, person('Barry', 'Drake'), date(15, 9,1996)). climb('Naturally', 14, person('Barry', 'Drake'), date(11,10,1997)). climb('The Picnic', 10, person('Dot', 'Kanga'), date(14, 2,1953)).
You should also add some comments at the start of your program describing its purpose, author and date. Comments start with the percent sign (%) and continue to the end of the line.
' are used here to construct
atoms; in SWI Prolog double quotes
" are used to
build strings. You can read about the differences in the
% prolog -s climbing.pl ... blah blah blah ... ?- female(Person). ?- male(Person).
Note that the Person variable gets bound to a structure.
?- male(person(_, LastName)).
Recall that the underscore (_) is a special variable where the results are not printed and different instances are not required to match.
?- climb('Roller', _, person(FirstName, LastName), _).
Notice that in order to find a fact in the database which would answer the question, Prolog performed a quite complex matching operation between the structures in the query and those in the head of the clause.
later(date(Day1, Month, Year), date(Day2, Month, Year)) :- !, Day1 > Day2. later(date(_, Month1, Year), date(_, Month2, Year)) :- !, Month1 > Month2. later(date(_, _, Year1), date(_, _, Year2)) :- Year1 > Year2.
Note that the cuts indicate that if Prolog has found a clause head which matches the goal then there is no need to consider the following clauses.
Add this new predicate to
climbing.pl and re-consult.
, and the name of the functor for a list, written as a term, is
.(Head, Tail)is the term for a list whose head is
Headand whose tail is
Let's define a predicate,
is_a_list, which succeeds
if its argument is a list:
is_a_list(). is_a_list(.(Head, Tail)) :- is_a_list(Tail).All we have done here is to write a predicate which tests whether a particular term is a list or not.
Using our definition, a list of numbers
[a, b, c] would
be written using the notation:
.(a, .(b, .(c, )))How would the following lists be represented using the
lists.pland add the predicate
is_a_list. Try the following queries...
?- is_a_list(). ?- is_a_list(.(a, )). ?- is_a_list(.(a, b)). ?- is_a_list(a).
Explain how Prolog arrived at the results for each query.
head_tail(List, Head, Tail), which will extract the
Add this to the
lists.pl file and test your program...
% prolog -s lists.pl ... blah blah blah ... ?- head_tail(.(1, .(2, .(3, ))), Head, Tail). Head = 1, Tail = [2, 3].
% base case is_member(Element, list(Element, _)). % recursive case (to be completed!) is_member(Element, list(_, Tail)) :- INSERT CODE HERE
Add the complete code for
?- is_member(1, list(1, list(2, list(3, nil)))). true. ?- is_member(3, list(1, list(2, list(3, nil)))). true. ?- is_member(5, list(1, list(2, list(3, nil)))). false. ?- is_member(nil, list(1, list(2, list(3, nil)))). false.
?- is_member(X, list(1, list(2, list(3, nil)))).
[1, 2, 3]. Internally, Prolog still stores the list as if it were entered in the prefix form. To get some idea of how the compact list notation works we'll look at some queries and their responses. First try this one:
?- [X, Y, Z] = [1, 2, 3]. X = 1 ; Y = 2 ; Z = 3 ;
This query asks Prolog to match (or unify) the two terms on either side of the equals sign. If a variable appears in a position corresponding to an element in the second list then that variable is unified with the element.
?- [1, 2, 3] = [Head | Tail]. Head = 1 Tail = [2, 3]
?- [1, 2, 3, 4, 5, 6] = [Head | Tail]. ?- [1, 2] = [Head | Tail]. ?-  = [Head | Tail]. ?-  = [Head | Tail]. ?- [Head | Tail] = [[1, 2], [3, 4, [5, 6]], [7, 8], 9]. ?- What = [a | [b, c, d]]. ?- What = [a | [b]]. ?- What = [[a] | [b]]. ?- What = [a | b].
prologhas a built-in predicate,
member, which operates in a way similar to
is_memberabove. However (depending on which version of SWI-Prolog you are using)
membermight only work on [...]-style lists (just as
is_memberonly works on list(...)-style lists). Repeat the membership queries using
?- member(1, [1, 2, 3]). ?- member(3, [1, 2, 3]). ?- member(5, [1, 2, 3]). ?- member(, [1, 2, 3]).
member(as shown) and the equivalent
is_memberusing our earlier notation. You will need to translate the list representation to our earlier format to use
?- member(X, [a, b, c]). ?- member(a, List).
In what way do the predicates
is_member behave differently?
cons, to concatenate two lists.
: cons([1, 2, 3], [4, 5, 6], Result)? Result = [1, 2, 3, 4, 5, 6]
descendant, in the
family.plprogram. Reload that program and test the predicate to remind yourself how it works.
% prolog -s family.pl ... blah blah blah ... ?- descendant(albert,Descendant).
This query shows all the descendants of Albert.
Prologprovides a predicate,
findall, to put all the responses from such a query into a Prolog list. Try the following:
?- findall(D, descendant(albert,D), List).
The first argument is a variable which is used temporarily to indicate what should be put in the list (third argument) when solutions are found to the goal (second argument).
findallto write a new predicate,
children(Parent, ChildList), where ChildList is the list of children of Parent. Then test the new predicate. For example:
?- children(irene, Children). Children = [jim, peter] ?- children(peter, Children). Children = [lee, sandra, james, kate, kyle] ?- children(lee, Children). Children = 
siblings(Child1, Child2), to return whether two people are brothers or sisters. Write a new predicate,
sibling_list(Child, Siblings), which returns a list of the Child's siblings. Test the new predicate...
?- sibling_list(sandra, Siblings). Siblings = [lee, james, kate, kyle] ?- sibling_list(jim, Siblings). Siblings = [peter] ?- sibling_list(brian, Siblings). Siblings = [darren]
You will need to deal with the problem of duplicated siblings!
?- Expr = 1 + 2 * 3 + 4. ?- Expr = (a + 5) / b.
Prolog will not evaluate expressions unless it is explicitly forced to.
is, will force an arithmetic structure to be evaluated. Try these:
?- Expr is 1 + 2 * 3 + 4. ?- Expr is (1 + 2) * (3 + 4). ?- Expr is 10.
isis used on a structure which cannot be calculated an error will be printed. For example:
?- Expr is (a + 5) / b . ERROR: Arithmetic: `a/0' is not a function ?- Expr is 1 + 2 * 3 + X . ERROR: Arguments are not sufficiently instantiated
listCount(List, Count), to
family.plwhich will count the elements of the list. This will be a recursive predicate. This base case is for an empty list which has zero elements. The recursive case should add one to the count of the Tail. Write the
listCountpredicate then try it out:
?- listCount(, Count). Count = 0 ?- listCount([a, b, c], Count). Count = 3 ?- listCount([1, [2, 3], [, 5], 6], Count). Count = 4
findallto write a predicate,
countDescendants(Person, Count)which calculates how many descendants Person has.
?- countDescendants(albert, Count). Count = 9
deepListCountwhich counts all elements in the list and embedded lists. Here is some sample output:
?- deepListCount(, Count). Count = 0 ?- deepListCount([a, b, c], Count). Count = 3 ?- deepListCount([[a, b, c]], Count). Count = 3 ?- deepListCount([a, [b, c], [[d], e], f], Count). Count = 6
Solutions can be found here (when made available):
CRICOS Provider Code No. 00098G