PrologEZ
Data & computation · Lesson 14 of 43

A program as a database

Querying facts, existential and universal queries, records and the wildcard variable.

Logic programming patterns

The most relevant elements of Prolog as a programming language, with some useful programming (and design) patterns:

  • querying facts, existential queries, querying universal facts;
  • working with records, wildcard variables;
  • deriving knowledge with rules;
  • programming maths, and programming data types such as lists.

A Prolog program as a DB

  • Querying facts. A Prolog program with only ground facts can be seen as a database: all facts of a certain predicate (name and arity) form a table, and a single ground goal can be used to query the DB for a tuple.
  • Existential queries. If the goal has variables, you are really asking whether there exists an instantiation of the variables (a substitution) equating your goal with one or more facts. This is like searching multiple tuples with one query, and composing goals makes Prolog find combinations.
  • Universal facts. Variables in facts are quantified universally instead, hence a fact with variables is like an infinite set of facts.
  • Working with records. A fact can connect terms which are structured, e.g. in the form of records.
  • The wildcard variable, to avoid mentioning a variable once in a clause.

Querying facts

File querying-facts.pl.

male(isaac).
plus(2, 3, 5).
plus(1, 6, 7).
plus(0, 0, 5).
?- plus(2, 3, 5)
?- male(isaac)
?- plus(0, 0, 0)
?- plus(2, 3, 5), plus(1, 6, 7)

In resolution trees, yes is used to mean an empty resolvent (sometimes avoided altogether), and when there is no solution a no label is added. The tree for plus(2,3,5), plus(1,6,7) has a single branch: the first goal is solved, and the resolvent shrinks to plus(1,6,7), then to the empty one.

Existential queries

File existential-queries.pl. Each branch of the tree corresponds to a rule or fact unifying with the goal, and the unifier is taken as a solution.

plus(2, 3, 5).
plus(1, 6, 7).
plus(0, 0, 5).
?- plus(0, X, Y)
?- plus(X, Y, 5)
?- plus(X, Y, Y)

Existential queries and inherent exploration

Solving multiple goals inherently explores combinations, a bit like multiple clauses in a for-comprehension. Here, for each solution of the first goal, the second goal is explored in full:

?- plus(X, Y, Z), plus(W, K, Z)

Universal facts

File universal-facts.pl. A variable in a fact stands for infinitely many facts: unification with a universal fact creates a substitution mentioning variables of a cloned clause, which are not shown in the final result.

plus(0, X, X).
plus(X, 0, X).
?- plus(0, 3, 3)
?- plus(0, 5, R)
?- plus(3, 0, X)
?- plus(0, 0, X)

plus(3, 0, X) has no clash: the variable X of the first clause is a different variable from the one in the goal, thanks to renaming. And plus(0, 0, X) answers X = 0 twice, once per universal fact: both clauses apply.

Working with records

File records.pl. A fact can relate structured terms. Recall that manager is a predicate, person a functor. Prolog prints the minimal substitution.

manager(person(john, smith, 1283)).
clerk(person(jim, white, 3475)).
clerk(person(george, red, 8765)).
chief(person(john, smith, 1283), person(george, red, 8765)).
?- chief(X, person(Y, Z, 8765))

The wildcard variable

File wildcard.pl.

  • In programs, _ marks a variable used once in the clause.
  • In goals, it marks a variable we do not need to see in the solutions.

It is good Prolog practice to never use singleton variables in a clause, but wildcards instead. This avoids copy-and-paste errors in variable names.

p(_, 1).
p(1, 2).
q(_, a(1, _)).
r(X, a(1, X)).
?- p(X, 1)
?- p(1, Y)
?- p(1, _)
?- q(1, a(1, 2))
?- r(1, a(1, 2))

p(1, _) answers yes twice (both clauses match, and nothing is displayed for _). r(1, a(1, 2)) fails: unlike q, r repeats X, so the two positions must agree, and 1 ≠ 2.

Exercise: Records and a wildcard

The clerk/1 and manager/1 records are loaded. Write first_names(F): it should list the first names of the clerks, one per solution, using wildcards for the fields you do not need.