Previous | Table of Contents | Next |
The predicates in the genealogy program have two arguments each, but we can also have predicates with zero, one, three, or more arguments. As with constants, we dont declare predicates but simply use them with whatever arity we want. An example of a predicate with zero arguments might be rainy; the fact rainy in a Prolog program might be used to state that it is rainy today. rich might be used as a predicate with one argument: rich(henry_viii), for instance, might state that Henry VIII was rich. It is up to us to choose the predicate and constant names in a way that makes the resulting program readable.
In the genealogy program, the father relation is defined using five facts, each on a separate line and terminated by a dot; mother is defined using two facts. Facts, together with rules (such as the rule defining hello in section 6.2.1), are collectively known as clauses. A Prolog program, in general, is a list of clauses, each clause terminated by a dot. We can use any number of clauses to define a predicate, although most Prologs insist that the clauses defining a given predicate be grouped together. Because simple programs such as this in some sense sum up some knowledge about the world, they are often referred to as knowledge bases.
6.2.2.2. Querying the Genealogy Program
To see how Prolog uses such knowledge bases, we can load the genealogy program into a file named gene.pl and consult the file using [gene]. If we now issue the query
|?- father(henry_viii, henry_vii).
we are essentially asking Prolog to confirm that that fact is true, according to what it knows so far. Prolog of course answers yes; to the query father(henry_viii, richard_iii), it answers no.
Prologs strength is that it can not only confirm or deny facts, but also supply answers. When we pose the query father(henry_viii, X), we are asking Prolog to replace the variable X by something that makes the resulting fact true. Any sequence of alphanumeric characters and underscores beginning with an uppercase letter is a Prolog variable. When a variable X appears in a query, we can read the query as beginning Does there exist an X such that ? This sample query therefore says Does there exist an X such that X is the father of Henry VIII?
To this query, Prolog responds with
X = henry_vii ?
This output is not asking whether X can be henry_vii; rather, it is telling us that it can be and prompting us for whether we want to search for other Xs that make the query true. This prompt is called the solutions prompt. At a solutions prompt, if we press Enter, we get back to the query prompt. To see a case where Prolog can find more than one solution, we can enter the query father(Y, henry_vii). This query asks rather if there is an Y such that Y is a child of Henry VII. It should come back with the solutions prompt
Y = henry_viii ?
But Henry VII has two children in the knowledge base. If we type the semicolon character (;) at the solutions prompt and press Enter, we get the other solution:
Y = margaret_tudor ?
If we type ; and press Enter again in this example, we get simply no, indicating that there are no more solutions.
Note that we can put as many variables as we like in Prolog queries; in fact, if we enter the query father(Kid, Dad) and then keep entering semicolons, we should get a list of all child/father pairs in the program.
6.2.2.3. Rules
Section 6.2.1 shows some imperative expressions called rules. Rules are usually used, however, to state general conditions under which predicates hold. Here we look at some simple rules.
Add the following text to the genealogy program:
% parent(X, Y): Y is a parent of X parent(X, Y) :- father(X, Y). parent(X, Y) :- mother(X, Y).
These rules define a new predicate, parent. The :- symbol can be read as if; the clauses can be read as If Y is the father of X, then Y is a parent of X and If Y is the mother of X, then Y is a parent of X. If we reconsult the augmented program and issue the query parent(james_v_of_scotland, X), then we should get two answers, james_iv_of_scotland and margaret_tudor. Prolog has found the first answer by using the first rule and checking its collection of father facts. Because there is another clause defining the parent relation, Prolog then uses that clause and its mother facts to find the other solution.
Now consider the query parent(X, Parent), father(Parent, Grandfather). This asks Prolog to find three values, X, Parent, and Grandfather, such that Parent is the parent of X and Grandfather is the father of Parent. A comma-separated list of predicate calls is a request to satisfy all of them. When Prolog has finished looking, it should have been able to find four triples of people satisfying those conditions, such as
Grandfather = henry_vii, Parent = henry_viii, X = elizabeth_i
We can encode the relation that this query reflects by adding the following rule to the program:
grandfather(X, Grandfather) :- parent(X, Parent), father(Parent, Grandfather).
After this addition (and a reconsult), we can pose the query grandfather(X, Grandfather) and expect to get four answers again. Note, however, that Parent is here a variable local to the definition of grandfather and thus does not get reported in the result. As in other languages, local variables can be used to hide details of the computation we are not interested in. Any variable that appears in the body of a rule but not in the head is local.
Previous | Table of Contents | Next |