Title: Prolog
1Prolog
- Prolog is a logic programming language based on
predicate calculus - Note that there are differences, as well as
similarities, between Prolog and predicate
calculus - We compute in Prolog by writing facts, rules and
queries - A fact tells something true about the world. It
looks like a predicate, but is used only for true
predicates - Ex teaches(prof_marling, ai).
- A rule shows a logical implication, but using
syntax that is the reverse of that used in
predicate calculus - Ex ?X (man(X) ? mortal(X)) --- predicate
calculus - Ex mortal(X) - man(X). --- Prolog
- A query looks like a fact, but asks whether a
predicate is true or false (for constants) or
what values would make the predicate true (for
variables) - Ex teaches(prof_marling,X).
2Some Notes on Syntax
- The name of a predicate or constant begins with a
lower-case letter, and may contain other letters,
digits, or underscores - The name of a variable begins with a capital
letter, and may contain other letters, digits, or
underscores - A Prolog fact, rule, or query ends with a period
- We distinguish between facts and queries, which
look alike, by context - In a Prolog program, we write facts
- At the Prolog interpreter prompt, we enter
queries - If we want to enter a fact into the interpreter
(perhaps for debugging purposes), we use the
built-in predicate assert - Ex assert(teaches(prof_marling,ai)).
- It is generally easier to keep facts in a file
and then load the file into the Prolog
interpreter using the syntax filename. - See Web page for info on how to run the Prolog
interpreter on prime
3More on Syntax
- The comma (,) is used to represent logical and
(?) in Prolog - Ex lucky_student(X) - takes(X,ai),
teaches(prof_marling,ai). - Logical or (?) is represented by multiple
statements having the same head, or left-hand
side - Ex ai_student(X) - takes(X,cs480).
- ai_student(X) - takes(X,cs580).
- As Luger points out, Prolog syntax allows the use
of the semi-colon () for logical or. Note that
this usage is rare and should be avoided for the
sake of clarity and style. - Legal, but not recommended
- ai_student(X) - takes(X,cs480)
takes(X,cs580).
4Quantifiers and Variables
- Predicate calculus and Prolog differ in the use
of quantifiers - Ex ?X (man(X) ? mortal(X)) ---
mortal(X) - man(X). - Quantifiers are not written in Prolog, but they
are implied - In a rule or a fact, all variables are
universally quantified - In a query, all variables are existentially
quantified - Ex eats(john,X).
- If this is a fact, it says, John eats
everything. - If this is a query, it asks, What does John
eat? - Variables with the same name in the same rule
refer to the same object - The scope of a variable is one whole rule, fact
or query - If there is a variable with the same name in two
different rules, facts or queries, they are
unrelated to each other - So, for the examples on this page, John is not a
cannibal
5Example Prolog Unifies Variables Using
Backtracking
- Some Prolog facts likes(joe ,bob_evans).
- likes(joe,
pizza_hut). - likes(ellen,
pizza_hut). - likes(ellen,
ponderosa). - A query likes(joe, X), likes(ellen, X).
- A trace Call likes(joe, _G388)
- Exit likes(joe, bob_evans)
- Call likes(ellen, bob_evans)
- Fail likes(ellen, bob_evans)
- Redo likes(joe, _G388)
- Exit likes(joe, pizza_hut).
- Call likes(ellen, pizza_hut)
- Exit likes(ellen, pizza_hut)
- X pizza_hut
-
6Another Example
- Say we had likes(joe, bob_evans).
- likes(joe, pizza_hut).
- likes(joe,
larrys_dawg_house). - likes(ellen, X).
- The Prolog interpreter would respond
- X bob_evans
-
- We could ask for additional answers with a
semi-colon - X pizza_hut
- X larrys_dog_house
- No
- Note that responses are given in a top-down order.
7You Try It!
- Prolog is fun.
- Jane always likes fun things.
- Something is fun if its entertaining or if Prof.
Marling says it is. - A trained collie is a good dog.
- Fred is trained.
- Fred is a collie.
- Does Jane like Prolog?
- Is Fred a good dog?
8The Closed World Assumption/Negation as Failure
- In our example, if Joe and Ellen also like
McDonalds and Dairy Queen, the interpreter
doesnt say so - It only knows the facts its given and what it
can infer from them - The closed world assumption says that anything
not provably true must be false - Prolog uses the ? operator in a limited way,
using this assumption - Ex likes(joe, mcdonalds).
- No
- not(likes(joe, mcdonalds)).
- Yes
- This is a kludge, not a positive feature, but it
makes it possible to deal with negation at some
level - Prolog programmers should understand how this
works
9I/O in Prolog
- I/O is necessary for a program to communicate
with users and to access files - It is procedural in nature, and does not follow
the logic programming paradigm - You can not backtrack and undo something which
has been read in or written by a Prolog program
when a goal fails - Example of interactive I/O using built-in
predicates read and write - io - write(?Enter a value for Y ?), read(Y),
nl, - write(?You entered ?), write(Y), nl.
- When you enter interactive input, input must end
with a period - If you need to enter spaces, enclose the whole
input in single quotes - Enter a value for Y 8.
- You entered 8
- Enter a value for Y ?hello, world?.
- You entered hello, world
10File I/O
- Only one input and one output stream are active
at a time - The default stream for both input and output is
the interactive user stream - Specify a desired input file with the predicate
see and a desired output file with the predicate
tell - Close files with the predicates seen and told
- Example Copy three things from infile to outfile
and tell the user when thats done - fileio - see(infile), tell(outfile),
read(X), read(Y), read(Z), - write(X), write(Y), write(Z),
seen, told, tell(user), - write(We are done).
- Note that the contents of the input file must be
formatted as for interactive input - For the example to work, infile must contain at
least three entries, each terminated by a period
11Lists and Recursion
- Lists are built in to Prolog
- Ex a, b, c, d
- red, blue, yellow, green,
purple, pink - a
- The head of a list is its first element and the
tail is the rest of the list - Ex Matching the above lists to X Y gives
- X a, Y b, c, d
- X red, blue, Y yellow, green,
purple, pink - X a, Y
- The empty list has no elements
- It is frequently used to terminate recursion in
list processing - Lugers example writes each element of a list on
one line - writelist().
- writelist(H T) - write(H), nl,
writelist(T).
12The Member Function
- Prolog has a built-in member predicate, which
tests to see if its first argument is contained
in its second - The second argument is assumed to be a list
- Ex member(1, 1, 2, 3).
- Yes
- member(1, 100, 101, 102, 103, 104).
- No
- member(X, 1, 2, 3).
- X 1
- X 2
- X 3
- No
13A Trace of the Member Function
- 1 member(X, X T).
- 2 member(X, Y T) - member(X, T).
- ?- member(c, a, b, c).
- call 1. fail, since c ? a
- call 2. X c, Y a, T b, c,
member(c, b, c)? - call 1. fail, since c ? b
- call 2. X c, Y b, T c,
member(c, c)? - call 1. success, c
c - yes (to second call 2.)
- yes (to first call 2.)
- yes
14Recursive Search Example The Knights Tour
- The knights tour is a classic problem in which
we try to find a series of legal - moves for a knight on a chessboard, such that
the knight visits every square on - the board exactly once.
Legal moves of a chess knight
A 3 ? 3 chessboard with move rules for the
simplifiedknight tour problem
15The Knights Tour in Prolog
- move(1, 6). move(3, 4). move(6, 7).
move(8, 3). - move(1, 8). move(3, 8). move(6, 1).
move(8, 1). - move(2, 7). move(4, 3). move(7, 6).
move(9, 4). - move(2, 9). move(4, 9). move(7, 2).
move(9, 2). - 1 path(Z, Z, L).
- 2 path(X, Y, L) - move(X, Z), not(member(Z,
L)), path(Z, Y, Z L).
16Trace of the Knights Tour
- ?- path(1, 3, 1).
- path(1, 3, 1) attempts to match rule 1. fail,
1 ? 3. - path(1, 3, 1) matches rule 2. X is 1, Y is 3, L
is 1 - move(1, Z) matches Z as 6, not(member(6, 1)) is
true, path(6, 3, 6, 1) - path(6, 3, 6, 1) attempts to match rule
1. fail, 6 ? 3. - path(6, 3, 6, 1) matches rule 2. X is 6,
Y is 3, L is 6, 1 - move(6, Z) matches Z as 7, not(member(7,
6, 1)) is true, path(7, 3, 7, 6, 1) - path(7, 3, 7, 6, 1) attempts to match
rule 1. fail, 7 ? 3. - path(7, 3, 7, 6, 1) matches rule 2. X
is 7, Y is 3, L is 7, 6, 1 - move(7, Z) matches Z as 6,
not(member(6, 7, 6, 1)) fails, backtrack! - move(7, Z) matches Z as 2,
not(member(2, 7, 6, 1)) true, path (2, 3, -
2, 7, 6, 1)
17Trace, continued from path (2, 3, 2, 7, 6, 1)
- path(2, 3, 2, 7, 6, 1) attempts to match rule
1. fail, 2 ? 3 - path(2, 3, 2, 7, 6, 1 matches rule 2. X is 2, Y
is 3, L is 2, 7, 6, 1 - move matches Z as 7, not(member (7, 2, 7, 6,
1)) fails, backtrack! - move matches Z as 9, not(member (9, 2, 7, 6,
1)) true, path(9, 3, -
9, 2,
7, 6, 1) - path attempts to match rule 1. fail, 9 ? 3
- path matches rule 2, X is 9, Y is 3, L is 9,
2, 7, 6, 2) - move matches Z as 4, not(member(4, 9, 2, 7,
6, 2)) true, path (4, 3, -
4, 9, 2,
7, 6, 1) - path attempts to match rule 1. fail, 4 ?
3 - path matches rule 2. X is 4, Y is 3, L
is 4, 9, 2, 7, 6, 1 - move matches Z as 3, not(member(3, 4,
9, 2, 7, 6, 1 true, path -
(3, 3, 4,
9, 2, 7, 6, 1) - path attempts to match rule 1.
true, 3 3, yes - Now we can answer each recursive call with a yes,
all the way up to the top!
18The Use of Cut (!) in Prolog
- Cut is not part of predicate calculus
- It was added to Prolog to allow the programmer to
control search, thereby improving efficiency - Cut is used in the right-hand-side of a Prolog
rule - As a goal, cut always succeeds the first time it
is encountered - It then blocks any backtracking to preceding
parts of the rule - This has the effect of stopping search along a
particular path
19Example Using Cut
- move(1, 6). move(6, 1).
- move(1, 8). move (8, 3).
- move(6, 7). move(8, 1).
- path2(X, Y) - move(X, Z), move(Z, Y).
- path2cut(X, Y) - move(X, Z), !, move(Z, Y).
- ?- path2(1, W).
?- path2cut(1, W). - W 7
W 7 -
- W 1
W 1 -
- W 3
no -
- W 1
-
- no
20Sample Program with Cut, I/O, Arithmetic, and
Recursion
double - write('Enter a number to double, or
q to quit '), read(X),
process(X). process(q) - !. process(N) -
D is N 2, write('The double of '),
write(N), write(' is '), write(D), nl, double.
21Running the Sample Program
double. Enter a number to double or q to
quit 10. The double of 10 is 20 Enter a number
to double or q to quit 33. The double of 33 is
66 Enter a number to double or q to quit q. Yes
22Arithmetic Using is in Prolog
- You can do simple arithmetic in Prolog, using the
operators , -, , / - The comparison operators gt, lt, gt, lt, , and
\ are also built in - Note To compare non-numeric values, use
instead of for equality and \ instead of
\ for inequality - The is operator is not an ordinary assignment!!!
Heres how it works - The variable on the left-hand side must not be
instantiated - All variables on the right-hand side must be
instantiated - The variable on the left-hand side is then
instantiated with the value calculated for the
right-hand side - Otherwise, the goal fails
- So, you can never have a statement like
- A is A 1
- This is guaranteed to fail, because A is either
instantiated or not
23You Try It!
- Write a Prolog predicate exchange(X, Y) to change
American dollars into British pounds using the
exchange rate one dollar equals .66 pounds. Ex
exchange(100, Z). - Z 66
- Write a Prolog predicate minimum(X, Y, Z) to
instantiate Z to the minimum of X or Y. Ex
minimum(3, 4, M). - M
3
24Abstract Data Types in Prolog
- The list is a built in data structure that can be
used to define ADTs - Luger defines Prolog operations for
- the stack, a last in first out list
- the queue, a first in first out list
- the priority queue, a sorted, best out first list
- the set, an unordered list of non-duplicate
elements - We will review the stack together --- code for
all ADTs is in the Prolog file adts.pl, available
from our class home page - Recall that the stack is the ADT used in the
depth-first search - The first stack predicate is empty_stack().
- Depending on use, this can create a new empty
stack or test an existing stack to see if it is
empty
25More on Stacks
- stack(Top, Stack, Top Stack).
- Depending on which variables are bound to values,
this predicate can be used to - peek at the top (the first argument)
- push a new value (the first argument) onto the
stack (the second argument) to create a new stack
(the third argument) - pop a value (the first argument) from the stack
(the third argument) to create a new stack (the
second argument) - member_stack(Element, Stack) - member(Element,
Stack). - This predicate tests whether an element is in the
stack - add_list_to_stack(List, Stack, Result) -
append(List, Stack, Result). - All elements of the first argument are appended
to the front of the list in the second argument
to obtain the value of the third argument
26And Still More on Stacks
- Because a stack may be used in search to maintain
a list of the visited states, it is often useful
to print out this list when a goal is reached - Because the states are pushed on the stack from
the start to the goal, the path followed is
stored in reverse order - Luger provides the predicate
- reverse_print_stack(S) - empty_stack(S).
- reverse_print_stack(S) -
- stack(E, Rest, S),
- reverse_print_stack(Rest),
- write(E), nl.
- Once we define operations like these on ADTs,
they can be used like any other predicates in
Prolog programs
27The Farmer, Wolf, Goat and Cabbage Problem In
Words
- A farmer with his wolf, goat, and cabbage come to
the edge of a river they - wish to cross. There is a boat at the rivers
edge, but, of course, only the - farmer can row. The boat also can carry only two
things (including the - rower) at a time. If the wolf is ever left alone
with the goat, the wolf will eat - the goat similarly, if the goat is left alone
with the cabbage, the goat will eat - the cabbage. Devise a sequence of crossings of
the river so that all four - characters arrive safely on the other side of the
river.
28The Farmer, Wolf, Goat and Cabbage Problem A
Picture
29The Farmer, Wolf, Goat and Cabbage ProblemPart
of a State Space Graph (with unsafe states)
30The Farmer, Wolf, Goat and Cabbage Problem in
Prolog
- We set up a data structure, state(F, W, G, C)
- While state is a predicate, thats not the most
useful view of state - We can think of state as a data structure with
four components, each of which can have the value
w for west or e for east - The start state for the problem is state(w, w,
w, w) - All four characters are on the west bank of the
river - The goal state is state(e, e, e, e)
- The predicate opp defines opposite banks of the
river with two facts - opp(e, w).
- opp(w, e).
- The predicate unsafe defines eating opportunities
with two rules - unsafe(state(X, Y, Y, C)) - opp(X, Y).
- unsafe(state(X, W, Y, Y)) - opp(X, Y).
31More Prolog for the FWGC Problem
- Since only the farmer can row, and at most two
characters fit in the boat at once, there are
only four possible moves - The farmer crosses alone, or with one of the
other three characters - The rule for moving the farmer and the wolf
across the river is - move(state(X, X, G, C), state(Y, Y, G, C))
- - opp(X, Y),
- not(unsafe(state(Y, Y, G, C))),
- writelist(try farmer takes wolf, Y,
Y, G, C). - There are three analogous rules for the other
possible moves, plus one rule for backtracking
when none of the four moves are possible - move(state(F, W, G, C), state(F, W, G, C))
- - writelist(backtrack from, F, W, G,
C), - fail.
- This rule must be placed after the other four, so
it is only fired when all else fails
32Finding a Path from the Start State to the Goal
State
- We want to find a sequence of moves that solves
the problem, so we keep track of where weve been
on a stack - When we reach the goal, all we have to do is
print the stack contents - path(Goal, Goal, Been_stack) -
- write(Solution Path Is), nl,
- reverse_print_stack(Been_stack).
- Until then, we find a path
- path(State, Goal, Been_stack) -
- move(State, Next_state),
- not(member_stack(Next_state,
Been_stack)), - stack(Next_state, Been_stack,
New_been_stack), - path(Next_state, Goal, New_been_stack),
!.
33Running the Code
- The go predicate starts the system by
initializing a stack and requesting a path from
the start to the goal state - go(Start, Goal) -
- empty_stack(Empty_been_stack),
- stack(Start, Empty_been_stack,
Been_stack), - path(Start, Goal, Been_stack).
- To run the code, enter
- go(state(w, w, w, w), state(e, e, e, e)).
- Note This code is available online. Running and
tracing it is very informative! So is modifying
it to see the effects of your changes.
34Running the Code (continued)
- ?- go(state(w,w,w,w), state(e,e,e,e)).
- try farmer takes goat e w e w
Solution path is - try farmer takes self w w e w
state(w,w,w,w) - try farmer takes wolf e e e w
state(e,w,e,w) - try farmer takes goat w e w w
state(w.w.e.w) - try farmer takes cabbage e e w e
state(e.e.e.w) - try farmer takes wolf w w w e
state(w.e.w.w) - try farmer takes goat e w e e
state(e,e,w,e) - BACKTRACK from e,w,e,e
state(w.e.w.e) - BACKTRACK from w,w,w,e
state(e,e,e,e) - try farmer takes self w e w e
- try farmer takes goat e e e e
35A Final Example The Financial Adviser Revisited
- A translation of the predicate calculus financial
advisor from Chapter 2 is available online - The code has been extended to allow interactive
input - Translating the first three rules into Prolog was
straightforward - investment(savings) - savings_account(inadequate)
. - investment(stocks) - savings_account(adequate),
income(adequate). - investment(combination) - savings_account(adequat
e), income(inadequate).
36Example, Continued
- The minsavings and minincome predicates have to
be defined according to Prologs conventions for
arithmetic - minsavings(X, Y) - Y is X 5000.
- minincome(X, Y) - Y is 15000 (4000 X).
- Then statements 4 through 8 can be written
- savings_account(adequate) - amount_saved(X),
dependents(Y), - minsavings(Y, Z), X gt Z.
- savings_account(inadequate) -
amount_saved(X), dependents(Y), - minsavings(Y, Z), X lt Z.
- income(adequate) - earnings(X, steady),
dependents(Y), - minincome(Y, Z), X gt Z.
- income(inadequate) - earnings(X, steady),
dependents(Y), - minincome(Y, Z), X lt Z.
- income(inadequate) - earnings(X, unsteady).
37The End of the Example
- Statements 9 through 11 are already perfectly
good Prolog facts! - amount_saved(22000).
- earnings(25000, steady).
- dependents(3).
- The translation available online omits these
facts and adds code so that the amount_saved,
earnings, and dependents can be entered by the
user - Running and tracing this code is highly
recommended!