north(sd, la). /* north of SD is LA */ north(la, sf). /* north of LA is SF */ north(X, Y) :- south(Y, X). /* Y is to the north of X if X is to the south of Y*/ north(X, Y) :- north(X, Z), north(Z, Y). /* Y is to the north of X if Z is to the north of X and Y is to the north of Y */ south(sd, mc). /* MC is to the south of SD */Assume that the above program is stored in a file
directions
.
The following is the transcript of a sesssion with the interpreter.
ieng9.ucsd.edu% sbprolog | ?- consult(directions). /* load the program */ yes | ?- north(sd, sf). /* query */ yes | ?- north(mc, sf). yes | ?- north(mc, X). X = sd; /* user types ";" */ X = la; X = sf; Heap overflow
sbprolog
at the prompt to start the interpreter.
If your prolog code is in a file named prologCode
,
type consult(prologCode)
to load your program. It is better
to avoid .
character in file names.(That is, avoid file
extensions for Prolog programs.) Type control-D to exit the interpreter.
A constant can be numeric, like 1
, 3.14159
, etc. or
symbolic, like sd
, sf
, etc. Note that
symbolic constants start with lower case alphabets.
A variable starts with an upper case letter. Examples of variables are
X
, City
, etc. There is one special
anonymous variable _
.
While constants and variables are used to represent objects, predicates are used to represent relations. The difference between functions and relations are
{<rose, red>, <leaf, green>, <sky, blue>, ...}is a function, the set
{<rose, red>, <rose, white>, <leaf, brown>, <sky, blue>, <sky, dark>, ...}is not a function. It is a relation. As you can see, it is sometimes easier to model real world observations as relations.
color(rose, red). color(rose, white). color(leaf, brown). /* others */Here
color
is a predicate of two arguments. Relations listed
in this form are called facts. Relations between relations can be expressed
in the form of rules. For example, we can say that the color of an object is
the color of its dominant part. This can be expressed as
color(X, Y) :- dominantPart(X, Z), color(Z, Y).
:-
is read as "if" and ,
as "and".
Note the use of variables to propagate bindings across predicates.
Thus a Prolog program consists of facts and rules. Rules have a head and a body. The prolog interpreter accepts query about the program and finds the solution through search.
algorithm = logic + controlThe programmer specifies the "logic" part (facts and rules pertaining to the problem) and the system supplies the "control" part (figuring out which rules to use logic to solve the problem). This is done by reading the rules in two ways. Suppose we have a rule
north(X, Y) :- south(Y, X)
. There are two ways of interpreting
this.
color(X, Y)
matches with
color(rose, red)
with the binding X=rose, Y=red
.
The pattern color(X, X)
does not match with the same predicate.
(This requires a predicate of the form color(rose,rose)
.)
Pattern matching is done between a goal and the head of a rule. The bindings created by pattern matching are propagated to the body of the rule.
If the query matches the head of a rule, the body of the rule is taken
for proving. The following figure shows the complete search process
for the query north(sd, sf)
.
north(sd, X)
returns the bindings
X = la
and X = sf
. (The system gets into a loop
after that!)
append([], Y, Y). append([H|X], Y, [H|Z]) :- append(X, Y, Z).The following are some queries to this program.
| ?- append([1,2],[3,4],X). X = [1,2,3,4]; no | ?- append([1,2],[3,4],[1,2,3,4]). yes | ?- append(X,[3,4], [1,2,3,4]). X = [1,2]; no | ?- append([1],[2],[1,2,3]). no | ?- append(X, Y, [1, 2]). X = [] Y = [1,2]; X = [1] Y = [2]; X = [1,2] Y = []; noThis is an example of a predicate which you can use in more ways than the number of lines it contains!
Note that the order in which the facts and rules are listed and the order in which the predicates are ordered in the rule body influences the search.
Suppose you are searching a sorted list. If the head of the list is greater than the key, there is no need to continue.
search(X, [Y|Z]) :- X = Y. search(X, [Y|Z]) :- X>Y, search(X, Z). search(X, [Y|Z]) :- X<Y, fail.Consider the Treasure Hunt example. If you find the Treasure, you do not want to backtrack. In this case, you can use a cut to prevent backtracking.
findTreasure(X) :- ..., whatIs(i, X), X = treasure,!, ...In this case, control never backtracks past cut. If for some reason the body after the cut fails,
whatIs
is never called again. In terms
of search tree, Prolog interpreter does not keep the control information
required for backtracking.
for_loop (Index, Final, Result) :- Index < Final, body_of_loop(Result), NewIndex = Index + 1, !, /* cut prevents unnecessary backtracking */ for_loop(NewIndex, Final, Result). /* Tail recursion: can be optimized by the interpreter */ for_loop (Index, Final, Result) :- Index >= Final.
repeat
loop.
repeat. repeat :- repeat;
lookup(K, V, [(K,W)|_]) :- V=W.Suppose we give the goal
lookup(a, 1, X).What's the result? Variable
X
unifies with the list
[(a,1)|_]
. This is a list whose last element is a variable! Such
lists are said to be open. Note that the effect of this rule is to add
a new element to the list. Consider the following program.
lookup(K, V, [(K,W)|_]) :- !, V=W. lookup(K, V, [_|Z]) :- lookup(K, V, Z).Now consider its uses.
| ?- lookup(a,1,X). X = [(a , 1)|_1492136] yes | ?- lookup(a,1,X),lookup(b,2,X). X = [(a , 1),(b , 2)|_1492368] yes | ?- lookup(a,1,X),lookup(b,2,X),lookup(a,Y,X). X = [(a , 1),(b , 2)|_1492584] Y = 1 yes | ?-The interesting aspects of Prolog are