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.