PrologEZ
Foundations · Lesson 6 of 43

The parent/child knowledge base

Four ground facts, then rules for grandparents and siblings, and what they can answer.

Example 1: the parent/child knowledge base

Program file: parent.pl.

A simple logic program with four ground facts representing one sort of relation between elements of the domain of discourse. Is there anything we can do with this program? Can we compute anything?

parent(joey, luca).
parent(joey, simone).
parent(lino, joey).
parent(mirella, joey).
  • joey, luca, simone, lino and mirella are constants used in the program as ground terms to denote the elements of the domain of discourse. (Is there a pre-interpretation? Yes: we decide that they stand for people.)
  • parent is the predicate used in the program to talk about the domain of discourse. parent/2 says that parent is the predicate symbol with arity 2.

Since the only predicate in the program is parent/2, we cannot prove anything else, in principle, except for tautologies or built-in predicates. The possible goals are:

?- parent(joey, luca)
?- parent(joey, lino)
?- parent(joey, Child)
?- parent(Parent, joey)
?- parent(Parent, Child)
?- parent(Grandparent, Parent), parent(Parent, Child)

Remarks on interaction

Interacting with a Prolog system, you can observe several things:

  1. success: the goal can be proved (true);
  2. failure: it cannot (false);
  3. computed substitution: the values found for the variables of the goal;
  4. unification: goal and clause heads are matched, not compared;
  5. backtracking: more answers come from the alternatives left behind;
  6. clause order: answers appear in the order of the clauses;
  7. no input/output parameters: no direction is required for arguments in principle, thanks to unification. parent(joey, Child) and parent(Parent, joey) use the same predicate.

Example 2: a rule to infer grandparents

Program file: grandparent.pl. The same facts, plus a rule.

parent(joey, luca).
parent(joey, simone).
parent(lino, joey).
parent(mirella, joey).

grandparent(G, N) :-
    parent(G, P),
    parent(P, N).

The rule grandparent(G, N) :- parent(G, P), parent(P, N). is added to the knowledge base. Now the logic program is a collection of facts and rules. It is a so-called universal rule, meaning that the rule holds for any possible value of the variables.

Test the program with the following queries, and discuss all the results:

?- grandparent(lino, luca)
?- grandparent(lino, joey)
?- grandparent(lino, Nephew)
?- grandparent(Grandparent, simone)
?- grandparent(Grandparent, Nephew)

Example 2 again: a rule to infer siblings

Program file: sibling.pl. A different rule is added to the same facts.

parent(joey, luca).
parent(joey, simone).
parent(lino, joey).
parent(mirella, joey).

sibling(S1, S2) :-
    parent(P, S1),
    parent(P, S2),
    S1 \= S2.

All the previous theorems are still true: all previous computations are the same, and we are just adding new theorems based on a new rule.

The operator \=/2 represents an explicit computation over terms: it succeeds when the two arguments are terms that do not unify. All the other computations over terms until now were implicitly driven by goal unification.

Test the program with the following queries, and discuss all the results:

?- sibling(simone, luca)
?- sibling(lino, joey)
?- sibling(luca, Sibling)
?- sibling(Sibling, luca)
?- sibling(joey, Sibling)
?- sibling(Sibling1, Sibling2)

Why does sibling(joey, Sibling) fail? Because joey's only parents are lino and mirella, and each of them has only joey as a child, so the only candidate sibling is joey himself, which S1 \= S2 rejects.

Exercise: Great-grandparents

The parent/2 facts of the example are loaded. Write a rule greatgrandparent(G, N) for a person G who is a parent of a parent of a parent of N. (With these facts nobody qualifies yet, but your rule should work on any family.)