Prolog is widely used for developing complex applications, especially in the field of Artificial Intelligence. Prolog is also being used as the basis for a standard 'knowledge representation language' for the Semantic Web – the next generation of Internet technology.
Input and Output 69
List Processing 119
Specimen Solutions to Practical Exercises 185
Getting Started
Chapter Aims
Starting Prolog
In this book a sequence of user-entered goals will generally appear preceded by the ?- prompt. A sequence of one or more goals entered by the user at the prompt is often called a question.
Prolog Programs
The program can then be loaded for use by the Prolog system using the built-in predicate query. Once placed in the database, the clauses usually remain there until the user exits the Prolog system and can therefore be used to evaluate further goals entered by the user.
Data Objects in Prolog: Prolog Terms
If you are familiar with other programming languages, you may find it useful to think of a compound expression as representing a record structure. Each argument to a compound expression must be an expression, which can be of any type, including a compound expression.
Chapter Summary
A list is often considered to be a special type of compound term, but in this book it will be treated as a separate type of data object. Unlike the arity of a compound expression, the number of elements a list has does not have to be determined in advance when a program is written, as will be explained in Chapter 9.
Practical Exercise 1
Clauses and Predicates
- Clauses
- Predicates
- Loading Clauses
- Variables
If a variable appears at the head of a rule or fact, it is taken to indicate that the rule or fact applies to all possible values of the variable. As explained earlier, the variable A at the head of the clause (representing the first name in this case) stands for 'for all A' and is said to be universally quantified.
Practical Exercise 2
Satisfying Goals
Introduction
Unification
For example, the terms dog(X) and dog(fido) can be united by binding variable X to atom fido, that is, the terms owned(john,fido) and owned(P,Q) can be united by variables P and Q to bind to atoms john and fido, respectively.
Warning: A Note on Terminology
Unifying Call Terms
X and fido united, with variable X bound to the atom fido X and [a,b,c] united, with X bound to list [a,b,c]. Here the first arguments of the two compound terms are successfully united, with X bound to the atom London.
Evaluating Goals
Thus, the first goal in the body of Rule 1 is fulfilled, with Y attached to the angle of the atom. Prolog now tries to fulfill the goals in the body of Rule 2: write ('God Save the Queen!') and nl.
Backtracking
All the goals in the body of [P4] now pass, so the head of the clause, which in rewritten form is parent(john,mary), passes. All the goals in the body of [RF1] have now succeeded, so the main rich_father(gavin,lucy) succeeds, and in turn rich_father(A,B) succeeds with A and B bound to gavin and lucy, respectively.
Satisfying Goals: A Summary
Search the database clauses from top to bottom* until you find one whose head matches the target. Start at the top (for evaluation) or for the clause that matches when the goal was last met (for reevaluation).
Removing Common Variables
A Note on Declarative Programming
Rearranging the clauses in the program in any order will produce the same three answers, but possibly in a different order (try it!). Rearrange the order of the goals in the bodies of the two lines defining large_animal/1, for example to .
Practical Exercise 3
Clause [A2] is a recursive definition of more distant ancestry that can be read as 'X is the ancestor of Y if there is a person Z such that X is the parent of Z and Z is the ancestor of Y'. Find (using backtracking) the first two people that the Prolog system will identify as Louise's descendants.
Operators and Arithmetic
- Operators
- Arithmetic
- Equality Operators
- Logical Operators
The preceding description can be simplified by evaluating the second argument of the is/2 operator and then uniting that value to the first argument. If the first argument is an unbound variable, it is bound to the value of the second argument (as a side effect) and the target succeeds. If the first argument is a number or a bound variable with a numeric value, it is compared to the value of the second argument.
Disagreement between two clauses \=. The Term1\=Term2 target succeeds if Term1=Term2 fails, ie. the two terms cannot be unified.
Practical Exercise 4
Input and Output
- Outputting Terms
- Inputting Terms
- Input and Output Using Characters
- Outputting Characters
- Inputting Characters
- Using Characters: Examples
- Input and Output Using Files
- File Output: Changing the Current Output Stream
- File Input: Changing the Current Input Stream
- Reading from Files: End of File
- Reading from Files: End of Record
- Using Files: Examples
Prolog takes all input from the current input stream and writes all output to the current output stream. Evaluating a pointer scope causes the variable to be bound to the name of the current output stream. Evaluating a view scope causes the variable to be bound to the name of the current input stream.
Adapt the final program of Section 5.6 to read the characters in the text file myfile.txt until the * character is reached and output the number of vowels to the user terminal (ie, the screen).
Practical Exercise 5
Define and test a predicate combination that takes the names of two input files as its first two arguments and the name of an output file as its third argument. The output file must contain the terms in the first input file, followed by the terms in the second, one per line and terminated by end. Assume that both files contain the same number of terms and that the final term in each is end.
Loops
Looping a Fixed Number of Times
To perform the squares of the first N integers, perform the squares of the first N-1 and then perform N2. To perform the squares of the first N-1 integers, perform the squares of the first N-2 and then perform (N-1)2. To perform the squares of the first N-2 integers, perform the squares of the first N-3 and then perform (N-2)2.
To print the squares of the first 3 integers, print the squares of the first 2 and then 32.
Looping Until a Condition Is Satisfied
- Recursion
- Using the 'repeat' Predicate
The following program reads the first six terms from a specified file and writes them to the current output stream. Using the disjunction operator ;/2 defined in Section 4.4, the above program can be rewritten as a single clause. This recursive program repeatedly asks the user to enter a term until a yes or no is entered.
This program repeatedly asks the user to enter a term until yes or no is entered.
Backtracking with Failure
- Searching the Prolog Database
- Finding Multiple Solutions
The effect of using backtracking with an error in this case is to find all the teachers in the database. If the second allteachers statement were omitted, both teachers would still be found, but the evaluation of allteachers would fail. It should be noted that it is not always necessary to use "backtracking with error" to search the database.
Backtracking with failure can also be used to find all ways to accomplish a goal.
Practical Exercise 6
Preventing Backtracking
The Cut Predicate
The sumto/2 predicate definition given below is a slightly modified version of the one given in Chapter 6. The sumto(N,S) purpose causes the sum of the integers from 1 to N to be calculated and returns the answer as the value of S. Examples 1 and 2 can both be corrected by using additional purposes in the definition of predicates, e.g. by changing the second clause of the definition of greater to. and the second clause in the definition of sumto to.
However, the lack of cuts in the definition of the classify predicate leads to incorrect answers.
Cut with Failure
The can_fly (ostrich) objective is matched to the head of the first can_fly clause. The attempt to satisfy the goal in the body of that clause (i.e. fails) naturally fails, so the system next looks at the second can_fly clause. As before, the can_fly(ostrich) goal is matched to the head of the first can_fly clause.
An attempt to complete the goal in the body of this statement (ie failure) fails, but the cut prevents the system from backtracking, and so the can_fly(ostrich) goal fails.
Practical Exercise 7
Changing the Prolog Database
- Changing the Database: Adding and Deleting Clauses
- Adding Clauses
- Deleting Clauses
- Changing the Database: Example
- Maintaining a Database of Facts
The asserta/1 predicate causes Clause to be added to the database at the beginning of the series of clauses that define the corresponding predicate. It causes the first clause in the database that matches (i.e. unites with) the clause to be dropped. This shows that asserta places the new clause above the other mypred clauses in the database.
This shows that assertz places the new clause below the other mypred clauses in the database.
Practical Exercise 8
List Processing
- Representing Data as Lists
- Notation for Lists
- Decomposing a List
- Built-in Predicate: member
- Built-in Predicate: length
- Built-in Predicate: reverse
- Built-in Predicate: append
- List Processing: Examples
- Using findall/3 to Create a List
For example, the head of the list [dog, cat, fish, man] is the atomic dog, and the tail is the list [cat, fish, man]. If the first argument is an unbound variable, it is bound to an element in the list, working from left to right (ie, if called only once, it will be bound to the first element). If the second is an unbound variable, it is bound to the length of the list, i.e.
The rest of the list is passed to find_biggest as the first argument (a list of the numbers not yet explored).
Practical Exercise 9
String Processing
- Converting Strings of Characters To and From Lists
- Joining Two Strings
- Trimming a String
- Inputting a String of Characters
- Searching a String
- Dividing a String into Its Component Parts
Define and test a predicate trim/2 that takes a list of integers as its first argument and an unbound variable as its second and binds the variable to the list with any elements less than or equal to 32 removed on the left. In this case, the left part should be set to the separator and the right part should be set to the rest of the string. In this case, the right part should be set to the separator and the left part should be set to the rest of the string.
In this case the left part should be placed in string and the right part should be placed in .
Practical Exercise 10
More Advanced Features
- Extending Prolog: Arithmetic
- Extending Prolog: Operations on Strings
- Extending Prolog: Sets
- Processing Terms
With the new definition of the + operator, if any of its arguments is an expression like 5. The ** operator can be defined by adding the following clause to the definition of iss, anywhere except the final line (which is a 'catch is all'). The built-in predicate arg/3 can be used to find a specified argument of a compound term.
If the third argument is an unbound variable, it is bound to the value of the specified argument for the compound term.
Practical Exercise 11
Built-in Predicates
Stream can be the name of a disk file or an atom user (referring to a console input device). A stream is bound to the name of the current input stream, which can be a disk file or an atom user (which refers to a console input device). Sets the current output stream, which can be a disk file or an atom user (referring to the console output device).
Retrieves the current output stream, which can be a disk file or the atom user (referring to the console output device).
Built-in Operators
It succeeds if the value of the arithmetic expression Exp1 is less than the value of the arithmetic expression Exp2. It succeeds if the value of the arithmetic expression Exp1 is less than or equal to the value of the arithmetic expression Exp2. It succeeds if the value of the arithmetic expression Exp1 is greater than the value of the arithmetic expression Exp2.
Passes if the value of arithmetic expression Exp1 is greater than or equal to the value of arithmetic expression Exp2.
Specimen Solutions to Practical Exercises
The system starts by matching the target with the first clause defining the predicate ancestor/2, i.e. variables Desc,Y and Y1 are bound to each other and to caroline.X1 is bound to louise. The system tries to satisfy it again by connecting it to another clause for ancestor/2, ie.
Now all the goals in the body of [A2] succeeded, so the original goal ancestor(louise,Desc) succeeds with Desc bound to david.