CS 331 Spring 2025  >  A Quick Introduction to Prolog


CS 331 Spring 2025
A Quick Introduction to Prolog

By Glenn G. Chappell
Text updated: 2025-04-29

Table of Contents

  1. The Prolog Programming Language
  2. Predicates & Facts
  3. Variables
  4. Rules
  5. Unification
  6. Numbers
  7. Output & Loops
  8. Topics Not Covered
  9. Copyright & License

1. The Prolog Programming Language

History

Prolog is a programming language created in the early 1970s by a group led by Alain Colmeraur at the University of Aix-Marseille (France). The name “Prolog” is derived from PROgrammation en LOGique—French for “programming in logic”.

Prolog is the most popular of the logic programming languages, which are based on ideas developed by Stanford researcher Cordell Green in the 1960s. Green suggested that programs could consist of collections of logical statements—things that are true; execution of such a program would involve reasoning based on these logical statements.

There was a flurry of interest in Prolog in the 1970s. This has largely faded; however, a small but active Prolog community remains.

An ISO Prolog standard was issued in 1995 and most recently updated in 2000.

There are many versions of Prolog. The top three appear to be the following.

The remainder of this article will use SWI-Prolog.

Characteristics

Logic programming is a programming paradigm in which programs are collections of statements, and execution consists of the application of logical reasoning to statements, in order to solve problems.

Prolog is a logic programming language, that is, a PL based on the ideas underlying logic programming. A Prolog program is a representation of a knowledge base: a collections of things that are known. Execution involves attempts to determine whether certain statements are true and/or how they can be made true.

More specifically, a Prolog program consists of facts and rules. A fact is a logical statement that is known to be true. A rule is a way to find other true statements from those known.

Program execution is driven by a query: a question, roughly speaking. This can be a yes/no question or a what/who question. The computer attempts to answer the question using facts and rules from the knowledge base.

A query establishes a goal: something for the computer to try to show is true. During execution, various other goals, called subgoals, may be established.

The type system of most versions of Prolog—and of SWI-Prolog in particular—is much like that of Lua: dynamic, implicit, duck typing, new types cannot be created. However, in Prolog the notion of type is not very clearly developed. Type-like properties are checked in different ways in different contexts.

Execution & Conventions Used in This Article

Examples in this article assume the use of SWI-Prolog.

As with many modern programming languages, Prolog can be used interactively, and Prolog programs can be stored in source files. The filenames of Prolog source files traditionally end with either “.pl” or “.pro”. SWI-Prolog prefers the former, so we will use it (despite this suffix also being standard for the more popular Perl programming language).

We will store facts and rules in a source file, load these into the interactive environment, and initiate execution by entering queries at the interactive prompt.

In the interactive Prolog examples in this document, boldface typewriter-font characters are those typed by the user. Brownish non-bold typewriter-font characters show Prolog output. As you read this introduction, I recommend following along with SWI-Prolog.

To load a Prolog source file in SWI-Prolog, enter the filename in brackets at the prompt (“?-”), followed by a period. If the filename suffix is omitted, then “.pl” is appended to the filename. If a filename contains certain special characters (and it often does), then it will need to be enclosed in single quotes.

[Interactive Prolog]

?- [abc.pl].  % Loads abc.pl
true.

?- [abc].     % Also loads abc.pl
true.

?- ['a_b'].   % Loads a_b.pl - the quotes are required
true.

As shown above, after a sucessful file load, Prolog will print “true.”.

After a source file is loaded, queries may be entered based on the facts and rules the file contains.

If the last source file loaded has been modified, then we can reload it using make. As always, we need to place a period at the end.

[Interactive Prolog]

?- make.      % Reloads last loaded source file
true.

2. Predicates & Facts

Let’s enter information about a family tree into a Prolog source file. Say Alice has three children: Bob, Charlie, and Della. And Bob has two children: Ed and Flora.

To write these relationships in Prolog, we will use predicates. The meaning of this term is a little different in Prolog from its meaning in other contexts. Prolog does not make much use of functions, as we generally think of them. A Prolog predicate is something we might prove to be true—either on its own or applied to one or more values.

[Prolog]

parent(alice, bob).

The above line would be entered into a Prolog source file. It defines a predicate parent, which we are intending to represent an is-a-parent-of relationship. Here, alice and bob are atoms. They do not really mean anything; they are just words. Note that we must begin all of these with a lower-case letter.

parent(alice, bob)” is a Prolog fact: a statement that is known to be true. This fact represents the statement that Alice is a parent of Bob. When we enter a fact into Prolog, we must place a period after it.

Let’s write all the is-a-parent-of relationships as Prolog facts.

[Prolog]

parent(alice, bob).
parent(alice, charlie).
parent(alice, della).
parent(bob, ed).
parent(bob, flora).

If we place the above into a source file and load this file, we can then do queries based on the facts. Below are some queries and the output from Prolog.

[Interactive Prolog]

?- parent(alice, bob).
true.

?- parent(bob, alice).
false.

The first query above asks whether Alice is a parent of Bob. Prolog’s “true” says yes. The second asks whther Bob is a parent of Alice. Prolog’s “false” says no.

Note that we have not told Prolog that Bob is not Alice’s parent. But since we have not given Prolog the information required to prove this true, Prolog calls it false. Prolog’s result is not about truth, but provability. Prolog answers the second query above with “false” because it has failed to prove it true.

[Interactive Prolog]

?- parent(bob, flora).
true.

?- parent(alice, flora).
false.

?- parent(alice, gina).
false.

Note that we can ask about atoms that have not appeared in facts, as in the last query above.

3. Variables

The queries we have seen so far—like parent(alice, charlie)—have been yes/no questions: is Alice a parent of Charlie?

We can also ask what (or who) questions, using variables. Replacing an atom in a query with a variable tells Prolog to look for all possible values of the variable that form a true statement.

A Prolog variable name begins with an upper-case letter.

[Interactive Prolog]

?- parent(alice, X).
X = bob

Above, X is a variable. The query asks, Alice is the parent of whom?

If there is just one value of X that mades the query true, or if there are no values, then Prolog prints its output and gives the “?-” prompt again. But if there are multiple values, then it prints one, as above, and waits for keyboard input.

Pressing <Enter> ends execution. But pressing <Space> goes to the next solution. It may be necessary to press <Space> several times to see them all.

[Interactive Prolog]

?- parent(alice, X).
X = bob ;
X = charlie ;
X = della.

We can put a variable in other positions.

[Interactive Prolog]

?- parent(Who, charlie).
Who = alice.

And we can use multiple variables.

[Interactive Prolog]

?- parent(A, B).
A = alice,
B = bob ;
A = alice,
B = charlie ;
A = alice,
B = della ;
A = bob,
B = ed ;
A = bob,
B = flora.

4. Rules

A Prolog rule says that something is true if some other things are true.

Try adding the following at the end of the same source file that contains the ten “parent(…” facts. Then load the file again (if you are still in the same Prolog session, then you can reload with “make.”).

[Prolog]

grandparent(A, B) :- parent(A, X), parent(X, B).

The above is a rule. “grandparent(A, B)” is the head, and the part after “:-” is the tail. Essentially, this rule says that A is a grandparent of B if there is some X where A is the parent of X and X is the parent of B.

We have no facts for the grandparent predicate, but because of the rule, we can do meaningful queries.

[Interactive Prolog]

?- grandparent(alice, ed).
true.

?- grandparent(alice, X).
X = ed ;
X = flora ;
false.

?- grandparent(X, ed).
X = alice ;
false.

Note that, for each of the last two queries above, the results end with false. This has to do with the way results are computed; we do not need to worry about it at the moment.

5. Unification

To unify two constructions means to make them the same by binding variables (setting their values) as necessary.

=” is a Prolog predicate, written as an infix operator, that succeeds (is proven true) if its operands can be unified.

[Interactive Prolog]

?- aa = aa.
true.

?- aa = bb.
false.

?- X = aa.
X = aa.

For the last query, Prolog is saying that we can unify X with aa by setting variable X to aa.

Unification also works in the other direction.

[Interactive Prolog]

?- aa = X.
X = aa.

Things can get more interesting if we make lists of variables and/or atoms. Prolog lists use brackets and commas, much like Haskell lists.

[Interactive Prolog]

?- X = [aa, bb].
X = [aa, bb].

?- [X, Y] = [aa, bb].
X = aa,
Y = bb.

?- [X, bb] = [aa, Y].
X = aa,
Y = bb.

Let’s define a predicate that tells whether two people are siblings, based on the earlier parent data. This can be added to the same source file.

Two people are siblings if they have a common parent, right?

[Prolog]

sibling(A, B) :- parent(X, A), parent(X, B).

And a couple of queries.

[Interactive Prolog]

?- sibling(bob, charlie).
true.

?- sibling(bob, alice).
false.

?- sibling(bob, X).
X = bob ;
X = charlie ;
X = della.

The last query shows a flaw in our definition: actually, two people are siblings if they have a common parent, and they are different people.

The Prolog predicate “\=”, written as an infix operator, succeeds if its operands cannot be unified. So we can replace our previous rule for sibling with the following.

[Prolog]

sibling(A, B) :- parent(X, A), parent(X, B), A \= B.

This revised rule results in the behavior we want.

[Interactive Prolog]

?- sibling(bob, X).
X = charlie ;
X = della.

All Prolog execution actually works via unification. A query sets up a goal. To prove the query true, Prolog attempts to unify it with a fact, or with the head of a rule. Unification with the head of a rule is only allowed if the various parts of the tail of the rule can be proven true; these become subgoals, and so on.

6. Numbers

At this point, you might be wondering whether Prolog really counts as a programming language, rather than merely a database query language—perhaps something along the lines of SQL. But Prolog is actually a full-featured programming language, with numerical computation, flow of control, I/O, data structures, etc.

Let’s take a brief look at numbers in Prolog.

The predicate is, written as an infix operator, evaluates a numeric expression. The expression is given as the second operand of is, and is written largely as we would expect. The is succeeds if the first operand can be unified with the result of evaluating the second operand.

[Interactive Prolog]

?- 5 is 5.
true.

?- 6 is 2 * 3.
true.

?- 6 is 2 * 4.
false.

?- X is 2 * 3.
X = 6.

We can do numeric computations in Prolog using a predicate that takes two arguments: first, the input of a numeric function (its argument), and, second, the output of the same numeric function (its value)

[Prolog]

square(A, B) :- B is A*A.

The idea is that square(A, B) represents the statement that A squared is B.

[Interactive Prolog]

?- square(5, 25).
true.

?- square(5, 100).
false.

?- square(5, X).
X = 25.

One thing to watch out for when dealing with numbers in Prolog: the ordered comparison operators are as you expect, except for less-than-or-equal-to, which is written “=<”. I handle this by remembering that a Prolog numeric comparison operator never looks like an arrow.

7. Output & Loops

display is a predicate that takes one argument. It always succeeds, and it has the side effect of printing its argument to the standard output. nl is a predicate that takes no arguments and always succeeds, printing a newline to the standard output.

[Interactive Prolog]

?- display(99).
99
true.

?- nl.

true.

Note that a predicate with no arguments is not required to be followed by parentheses. Traditionally, these are always omitted, but SWI-Prolog allows you to include them if you wish.

[Interactive Prolog]

?- nl().

true.

Now let’s write a predicate for, which will begin a counted loop. We want for(I, 1, 10) to succeed once with I set to 1, then again with I set to 2, and so on, up to 10.

Another way to say this is that for(I, 1, 10) succeeds with I set to 1, and then does for(I, 2, 10). Furthermore, it never succeeds unless its second argument is less than or equal to its third argument.

Here is a first try at writing for.

[Prolog]

for(I, A, B) :- A =< B, I = A.
for(I, A, B) :- A =< B, for(I, A+1, B).

But the above has a problem. Expressions are not automatically evaluated in Prolog; the “A+1” is not converted into the value of A with 1 added unless we tell Prolog to do so.

The solution is to create a new variable that holds the integer after A, and set its value using “is”.

[Prolog]

for(I, A, B) :- A =< B, I = A.
for(I, A, B) :- A =< B, A1 is A+1, for(I, A1, B).

Now, let’s write a loop that prints the numbers 1 through 10, each on a separate line. We can start the loop with for(I, 1, 10), then do a display and then nl. But how do we end the loop?

Prolog finds solutions using a backtracking search. We can go to the next iteration of the loop by forcing Prolog to backtrack. To do this, we need a predicate that never succeeds. And here is it: fail. This takes no arguments.

Here, then, is a predicate print1to10 that takes no arguments and prints the numbers 1 through 10. It needs to go in the same file as our predicate for, above.

[Prolog]

print1to10 :- for(I, 1, 10), display(I), nl, fail.

And it works!

[Interactive Prolog]

?- print1to10.
1
2
3
4
5
6
7
8
9
10
false.

8. Topics Not Covered

This has only been a brief introduction. There is more to say about Prolog. Below are a few topics that were not covered here.

10. Copyright & License

© 2021–2025 Glenn G. Chappell

Creative Commons License
A Quick Introduction to Prolog is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.