Introduction to Prolog

GNU Prolog is installed on tux. You can load it my typing prolog.
You can download and install your own copy from http://www.gprolog.org/.

To quit prolog type Ctrl-D (end of file) or type "halt."
To load a file from the current directory, enter "[filename]." If the filename is .pl, you can leave off the file extension.
For example, to load last.pl you would enter "[last]." The period after the file name is required.

GNU Prolog 1.3.0
By Daniel Diaz
Copyright (C) 1999-2007 Daniel Diaz
| ?- [last].
compiling /home/au49/public_html/cs360/winter14/lab4/last.pl for byte code...
/home/au49/public_html/cs360/winter14/lab4/last.pl:1: warning: singleton variables [X] for last1/2
/home/au49/public_html/cs360/winter14/lab4/last.pl compiled, 0 lines read - 665 bytes written, 16 ms

yes

Variable names in prolog are always uppercase and constants/predicates are lower case. If you need to use a lower case name as a variable, you can but an underscore before it.

The append function is built into prolog. We can use it to append two lists together. Lists are contained in square brakets and elements are seperated by commas.

| ?- append([1,2,3],[4,5,6],X).

X = [1,2,3,4,5,6]

yes

Prolog outputs yes when it finds an answer that makes the result true.
We can ask it to determine if an answer is true or not.

| ?- append([1,2,3],[4,5,6],[1,2]).

no

Notice that the result it placed as the third input to the function. There is no concept of a return value, so we always need a function input to place the final answer in.
If a query has more then one answer, prolog will ask if we want to find more. It will give the first answer it finds followed by a question mark. You can type a semi-colon ; to find the next possible solution. You can enter the letter a to get all possible solution. If you just hit enter no more answers will be found.
Here is an example that finds all possible X and Y lists that append to a target list. Prolog prints out "no" when it reaches the final answer.

| ?- append(X,Y,[1,2,3,4,5]).

X = []
Y = [1,2,3,4,5] ? a

X = [1]
Y = [2,3,4,5]

X = [1,2]
Y = [3,4,5]

X = [1,2,3]
Y = [4,5]

X = [1,2,3,4]
Y = [5]

X = [1,2,3,4,5]
Y = []

no

We can define our own predicates in prolog. The easiest way to do this is by defining them in a file and including it.
Here is to code to redefine append. We can't redefine system predicates, so it will be called append1.

append1([], Y, Y).
append1([ A | B], Y, [A|W]) :- append1(B, Y, W).

The first definition of append says that if the first list is null then the only way to make the statement true is have the result be the second list. Think of the third variable as the return value. If the first list if null, we return the second list. The body of this command is empty. If it matches then it is true.
The second definition gives the recursive instructions for append.
A list can be broken into its head and tail using the vertical bar. [head | tail] makes head the first element and tail the remainder of the list.
The head of the second defintion says that the first element in the first list is appended to the beginning of the result list. The body check that the rest of the elements are correct.
We can use the trace command to see how the append is actually executed. Remember to turn off trace when you are done or you will get a huge amount of output.

| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- append1([1,2,3],[4,5,6],X).
1    1  Call: append1([1,2,3],[4,5,6],_28) ?
2    2  Call: append1([2,3],[4,5,6],_61) ?
3    3  Call: append1([3],[4,5,6],_88) ?
4    4  Call: append1([],[4,5,6],_115) ?
4    4  Exit: append1([],[4,5,6],[4,5,6]) ?
3    3  Exit: append1([3],[4,5,6],[3,4,5,6]) ?
2    2  Exit: append1([2,3],[4,5,6],[2,3,4,5,6]) ?
1    1  Exit: append1([1,2,3],[4,5,6],[1,2,3,4,5,6]) ?

X = [1,2,3,4,5,6]

yes
{trace}
| ?- notrace.
The debugger is switched off

yes

If you don't want to put all your definitions in file, you can define things from the command line.
First, type "[user]." to enter into user input mode. When you are done entering your commands type Crtl-D (end of file) and the code will be compiled.

| ?- [user].
compiling user for byte code...
append1([], Y, Y).
append1([ A | B], Y, [A|W]) :- append1(B, Y, W).

user compiled, 3 lines read - 469 bytes written, 6062 ms

yes

Using the bar syntax, we don't need the common list commands. We cna define them ourselves.

car([A|B],A).
cdr([A|B],B).
cons(A,X,[A|X]).

The below example asks what is a valid list to have the cdr [2,3,4]. Prolog returns the underscore in the first position to show that the value of the element can be anything.

| ?- cdr(X,[2,3,4]).

X = [_,2,3,4]

yes

The cut command ! can be used to stop backtracking. This limits the number of answers prolog will try to find.
First, lets look at an example without a cut.

a(X, Y) :- b(X), c(Y).
b(1).
b(2).
b(3).

c(1).
c(2).
c(3).

The comma symbol represents and. Both b(X) and c(X) need to be true. Now, we ask for every possible answer.

| ?- a(Q,R).

Q = 1
R = 1 ? a

Q = 1
R = 2

Q = 1
R = 3

Q = 2
R = 1

Q = 2
R = 2

Q = 2
R = 3

Q = 3
R = 1

Q = 3
R = 2

Q = 3
R = 3

yes

Notice that we got every value possible for Q or R.
Next, we can add a cut.

a(X, Y) :- b(X), !, c(Y).
b(1).
b(2).
b(3).

c(1).
c(2).
c(3).

The cut says, once a value is selected for b(X) never backtrack and change it.
Now, lets ask for all answers again.

| ?- a(Q,R).

Q = 1
R = 1 ? a

Q = 1
R = 2

Q = 1
R = 3

yes

This time we only got one value for Q because we told prolog to never backtrack and change that answer.

Here are some useful commands for defining predicates.
The or command is the semi-colon ;.
The not command is /=.
If we want math commands to be executed we can use is.
For example, X is 4 + 5.
Division is // For Example: X is 4 // 2.
The mod command is included X is 4 mod 3.