The Department of Computer Science & Engineering
 STUART C. SHAPIRO: CSE 305

# Logic Programming Languages: Prolog

Prolog, which stands for Programming in Logic, is the major logic programming language in current use. Although there are several variants, we will consider Prolog as implemented by the most usual compiler implementations.

Logic programming is also called relational programming, as opposed to functional programming.

Mathematical facts:

• For every function f(x1, ..., xk) = y, there is a relation, r(x1, ..., xk, y). If, for particular values, f(x1, ..., xk) does, indeed, equal y, than the relation r(x1, ..., xk, y) holds, or is true. On the other hand, if, for particular values, f(x1, ..., xk) does not equal y, than the relation r(x1, ..., xk, y) does not hold, or is false.
• A predicate function, f(x1, ..., xk), whose value is either true or false is the same as a relation.
Example1: Consider the Common Lisp function `append` that takes two lists and returns a list containing all the members of the first list followed by all the members of the second list. `append` is predefined in Common Lisp, but could be written as:
```test(10): (defun append (list1 list2)
(if (endp list1)
list2
(cons (first list1) (append (rest list1) list2))))
append

test(11): (append '(a b c) '(d e f))
(a b c d e f)
```
Notice that `append` is a function of the form f(x1, x2) = y, where if x1 = (a b c) and x2 = (d e f), then y = (a b c d e f).

The prolog version of `append` is a three-argument relation, `append(X, Y, Z)` which is true if `Z` is a list whose members are the members of `X` followed by the members of `Y`.

Note:

• Prolog names beginning with a lower-case letter are constant symbols or relation names.
• Prolog names beginning with an upper-case letter are variables.
• Prolog relations are written using normal "functional" notation.
Here is the Prolog version of append:
```append([], List2, List2).
append([First | Rest], List2, [First | Intermediate]) :-
append(Rest, List2, Intermediate).
```
And here is an interactive test of that program:
```<cirrus:Programs:1:103> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002

| ?- consult('append.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/append.prolog...
yes

| ?- append([a, b, c], [d, e, f], X).
X = [a,b,c,d,e,f] ?
yes

| ?- halt.
```
Interestingly, Prolog does not distinguish in parameters from out parameters. (They are all inout parameters.) It depends on which of the actual parameters are constants and which are variables. Here is another test of the append program:
```<cirrus:Programs:1:104> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002

| ?- consult('append.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/append.prolog...
yes

| ?- append([a, b, c], [d, e, f], X).
X = [a,b,c,d,e,f] ?
yes

| ?- append(X, [d, e, f], [a, b, c, d, e, f]).
X = [a,b,c] ?
yes

| ?- append([a, b, c], X, [a, b, c, d, e, f]).
X = [d,e,f] ?
yes

| ?- halt.
```
The top-level syntax of a Prolog program is
<program> -> {<clause>}

<clause> -> <fact> | <rule> | ?- <query>
<rule> -> <head> :- <body> .
<query> -> <body>.

<body> -> [<relation> {, <relation>}]

<relation> -> <predicate> [( <term> {, <term})]

You interact with Prolog by loading a program (by "consulting" a file), and then typing a query to the interactive system.

A <fact> is a relation that holds.

A <rule> says that the <head> holds if every <relation> in its <body> holds.

The set of <clause>s having the same <predicate> in their <head> constitutes a procedure for that <predicate>.

The scope of a variable is a single <clause> or <query>.

`append` was designed to compute the value of one actual argument when the other two were supplied. `member` is a two-argument relation designed to say whether its first argument is a member of the list which is its second argument. It is comparable to the Lisp `member` function:

```test(15): (defun member (obj list)
(cond ((endp list) nil)
((eql obj (first list)) t)
(t (member obj (rest list)))))
member

test(16): (member 'b '(a b c))
t

test(17): (member 'z '(a b c))
nil
```
Here is a first version of `member` in Prolog:
```member(Obj, [Obj | Rest]).
member(Obj, [First | Rest]) :- member(Obj, Rest).

------------------------------------------
<cirrus:Programs:1:106> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002
| ?- consult('member.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/member.prolog...
* [Rest] - singleton variables in user:member/2
* Approximate lines: 1-2, file: '/u0/faculty/shapiro/CSE305/Programs/member.prolog'
* [First] - singleton variables in user:member/2
* Approximate lines: 2-3, file: '/u0/faculty/shapiro/CSE305/Programs/member.prolog'
yes

| ?- halt.
```
The complaint is to a variable that appears in the head, but not in the body of a rule. Such a variable may appear as an "anonymous variable", written as `_`. No "anonymous variable" is the same as any other variable.

Here's the final version of `member` with some tests:

```member(Obj, [Obj | _]).
member(Obj, [_ | Rest]) :- member(Obj, Rest).

-----------------------------------------------
<cirrus:Programs:1:107> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002

| ?- consult('member.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/member.prolog...
yes

| ?- member(b, [a, b, c]).
yes

| ?- member(z, [a, b, c]).
no

| ?- halt.
```

The clauses in a procedure are tried in order, from the first to the last in the program, until one succeeds, thus constituting a multi-branch selection.

If the query contains a variable, then there may be multiple ways the program may succeed. The first way is shown, and the user may terminate the query by entering a CR, or may have the program find another way to succeed by entering `;`. If the user keeps doing this, the program will ultimately fail (when there are no more ways to succeed):

```<cirrus:Programs:1:108> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002

| ?- consult('member.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/member.prolog...
yes

| ?- member(X, [a, b, c]).
X = a ? ;
X = b ? ;
X = c ? ;
no

| ?- halt.
```
Parameter Passing
Prolog's parameter passing is by matching. Example:
```append([], List2, List2).
append([First | Rest], List2, [First | Intermediate]) :-
append(Rest, List2, Intermediate).

------------------------------------------------------------
<cirrus:Programs:1:127> sicstus
SICStus 3.9.1 (sparc-solaris-5.7): Thu Jun 27 22:58:18 MET DST 2002

| ?- consult('append.prolog').
% consulting /u0/faculty/shapiro/CSE305/Programs/append.prolog...
yes

| ?- append([X, b, [c], d], [e, X , Y], [a, b, [Y] | Z]).
X = a,
Y = c,
Z = [d,e,a,c] ?
yes
```
This figure shows the matching variables, and how information flows to instantiate them:

Arithmetic
Arithmetic operators evaluate their arguments, which must be instantiated (fully bound). The values of expressions may be bound to a variable with `is`. Note the difference between `=` and `is`.
```| ?- X = 3.
X = 3 ?
yes

| ?- 3 = X.
X = 3 ?
yes

| ?- X is 3.
X = 3 ?
yes

| ?- 3 is X.
! Instantiation error in argument 2 of is/2
! goal:  _73 is _74

| ?- X = 3 + 5.
X = 3+5 ?
yes

| ?- 3 + 5 = X.
X = 3+5 ?
yes

| ?- X is 3 + 5.
X = 8 ?
yes

| ?- 3 + 5 is X.
! Instantiation error in argument 2 of is/2
! goal:  _73 is _74
```

Sequence, Selection, and Loop
Statement-level control structures were illustrated by the echo.prolog program.
• Sequence is accomplished by successive relations in a body.

• Selection is accomplished by successive clauses in a procedure (clauses with the same predicate in their heads.)

• Loop is accomplished by recursion.

This version differs from the original in that it ends with a query that begins execution of the program. (Compare the automatic start of `main` in the C-based languages.

```echo :- format("~nType something to each prompt.~n\c
End every input with a period.~n\c
Type bye to quit.~2n", []),

format("~d: ", [N]),
echo_and_loop(N, X).

echo_and_loop(_, bye):- format("Good bye.~n", []), halt.
echo_and_loop(N, X) :-
N1 is N + 1,

?- echo.

-----------------------------------------------------------
<cirrus:Programs:1:129> sicstus -l echo.prolog
% compiling /u0/faculty/shapiro/CSE305/Programs/echo.prolog...

Type something to each prompt.
End every input with a period.
Type bye to quit.

1: 'Hello there'.
2: hi.
3: bye.
Good bye.

```factorial(0, 1).