A Second Look At Prolog

Download Report

Transcript A Second Look At Prolog

Prolog Tricks
Modern Programming Languages
1
Outline
20.6
 22.2
 22.3
 22.4

The Lighter Side of Prolog
Arithmetic in Prolog
Problem Space Search: 8 Queens
Farewell To Prolog
Modern Programming Languages
2
Quoted Atoms As Strings
Any string of characters enclosed in single
quotes is a term
 In fact, Prolog treats it as an atom:

–
–

'abc' is the same atom as abc
'hello world' and 'Hello world' are
atoms too
Quoted strings can use \n, \t, \', \\
Modern Programming Languages
3
Input and Output
?- write('Hello world').
Hello world
Yes
?- read(X).
|
hello.
X = hello
Yes
Simple term input and output.
 Also the predicate nl: equivalent to
write('\n')

Modern Programming Languages
4
Debugging With write
?- p.
[] [1, 2]
[1] [2]
[1, 2] []
No
p :append(X,Y,[1,2]),
write(X), write(' '), write(Y), write('\n'),
X=Y.
Modern Programming Languages
5
The assert Predicate
?- parent(joe,mary).
No
?- assert(parent(joe,mary)).
Yes
?- parent(joe,mary).
Yes

Adds a fact to the database (at the end)
Modern Programming Languages
6
The retract Predicate
?- parent(joe,mary).
Yes
?- retract(parent(joe,mary)).
Yes
?- parent(joe,mary).
No
Removes the first clause in the database that
unifies with the parameter
 Also retractall to remove all matches

Modern Programming Languages
7
Dangerous Curves Ahead




A very dirty trick: self-modifying code
Not safe, not declarative, not efficient—but can be
tempting, as the next example shows
Best to use them only for facts, only for predicates
not otherwise defined by the program, and only
where the clause order is not important
Note: if a predicate was compiled by consult,
SWI-Prolog will not permit its definition to be
changed by assert or retract
Modern Programming Languages
8
An Adventure Game

Prolog comments
–
–
/* to */, like Java
Also, % to end of line
/*
This is a little adventure game. There are three
entities: you, a treasure, and an ogre. There are
six places: a valley, a path, a cliff, a fork, a maze,
and a mountaintop. Your goal is to get the treasure
without being killed first.
*/
Modern Programming Languages
9
/*
First, text descriptions of all the places in
the game.
*/
description(valley,
'You are in a pleasant valley, with a trail ahead.').
description(path,
'You are on a path, with ravines on both sides.').
description(cliff,
'You are teetering on the edge of a cliff.').
description(fork,
'You are at a fork in the path.').
description(maze(_),
'You are in a maze of twisty trails, all alike.').
description(mountaintop,
'You are on the mountaintop.').
Modern Programming Languages
10
/*
report prints the description of your current
location.
*/
report :at(you,X),
description(X,Y),
write(Y), nl.
Modern Programming Languages
11
?- assert(at(you,cliff)).
Yes
?- report.
You are teetering on the edge of a cliff.
Yes
?- retract(at(you,cliff)).
Yes
?- assert(at(you,valley)).
Yes
?- report.
You are in a pleasant valley, with a trail ahead.
Yes
Modern Programming Languages
12
/*
These connect predicates establish the map.
The meaning of connect(X,Dir,Y) is that if you
are at X and you move in direction Dir, you
get to Y. Recognized directions are
forward, right and left.
*/
connect(valley,forward,path).
connect(path,right,cliff).
connect(path,left,cliff).
connect(path,forward,fork).
connect(fork,left,maze(0)).
connect(fork,right,mountaintop).
connect(maze(0),left,maze(1)).
connect(maze(1),right,maze(2)).
connect(maze(2),left,fork).
connect(maze(0),right,maze(3)).
connect(maze(_),_,maze(0)).
Modern Programming Languages
13
/*
move(Dir) moves you in direction Dir, then
prints the description of your new location.
*/
move(Dir) :at(you,Loc),
connect(Loc,Dir,Next),
retract(at(you,Loc)),
assert(at(you,Next)),
report.
/*
But if the argument was not a legal direction,
print an error message and don't move.
*/
move(_) :write('That is not a legal move.\n'),
report.
Modern Programming Languages
14
/*
Shorthand for moves.
*/
forward :- move(forward).
left :- move(left).
right :- move(right).
Modern Programming Languages
15
?- assert(at(you,valley)).
Yes
?- forward.
You are on a path, with ravines on both sides.
Yes
?- forward.
You are at a fork in the path.
Yes
?- forward.
That is not a legal move.
You are at a fork in the path.
Yes
Modern Programming Languages
16
/*
If you and the ogre are at the same place, it
kills you.
*/
ogre :at(ogre,Loc),
at(you,Loc),
write('An ogre sucks your brain out through\n'),
write('your eyesockets, and you die.\n'),
retract(at(you,Loc)),
assert(at(you,done)).
/*
But if you and the ogre are not in the same place,
nothing happens.
*/
ogre.
Modern Programming Languages
17
/*
If you and the treasure are at the same place, you
win.
*/
treasure :at(treasure,Loc),
at(you,Loc),
write('There is a treasure here.\n'),
write('Congratulations, you win!\n'),
retract(at(you,Loc)),
assert(at(you,done)).
/*
But if you and the treasure are not in the same
place, nothing happens.
*/
treasure.
Modern Programming Languages
18
/*
If you are at the cliff, you fall off and die.
*/
cliff :at(you,cliff),
write('You fall off and die.\n'),
retract(at(you,cliff)),
assert(at(you,done)).
/*
But if you are not at the cliff nothing happens.
*/
cliff.
Modern Programming Languages
19
/*
Main loop.
Stop if player won or lost.
*/
main :at(you,done),
write('Thanks for playing.\n').
/*
Main loop. Not done, so get a move from the user
and make it. Then run all our special behaviors.
Then repeat.
*/
main :write('\nNext move -- '),
read(Move),
call(Move),
ogre,
treasure,
The predefined predicate call(X)
cliff,
tries to prove X as a goal term.
main.
Modern Programming Languages
20
/*
This is the starting point for the game. We
assert the initial conditions, print an initial
report, then start the main loop.
*/
go :retractall(at(_,_)), % clean up from previous runs
assert(at(you,valley)),
assert(at(ogre,maze(3))),
assert(at(treasure,mountaintop)),
write('This is an adventure game. \n'),
write('Legal moves are left, right or forward.\n'),
write('End each move with a period.\n\n'),
report,
main.
Modern Programming Languages
21
?- go.
This is an adventure game.
Legal moves are left, right or forward.
End each move with a period.
You are in a pleasant valley, with a trail ahead.
Next move -- forward.
You are on a path, with ravines on both sides.
Next move -- forward.
You are at a fork in the path.
Next move -- right.
You are on the mountaintop.
There is a treasure here.
Congratulations, you win!
Thanks for playing.
Yes
Modern Programming Languages
22
Outline
20.6
 22.2
 22.3
 22.4

The Lighter Side of Prolog
Arithmetic in Prolog
Problem Space Search: 8 Queens
Farewell To Prolog
Modern Programming Languages
23
Unevaluated Terms
Prolog operators allow terms to be written
more concisely, but are not evaluated
 These are all the same Prolog term:

+(1,*(2,3))
1+ *(2,3)
+(1,2*3)
(1+(2*3))
1+2*3

That term does not unify with 7
Modern Programming Languages
24
Evaluating Expressions
?- X is 1+2*3.
X = 7
Yes
The predefined predicate is can be used to
evaluate a term that is a numeric expression
 is(X,Y) evaluates the term Y and unifies
X with the resulting atom
 It is usually used as an operator

Modern Programming Languages
25
Instantiation Is Required
?- Y=X+2, X=1.
Y = 1+2
X = 1
Yes
?- Y is X+2, X=1.
ERROR: Arguments are not sufficiently instantiated
?- X=1, Y is X+2.
X = 1
Y = 3
Yes
Modern Programming Languages
26
Evaluable Predicates
For X is Y, the predicates that appear in Y
have to be evaluable predicates
 This includes things like the predefined
operators +, -, * and /


There are also other predefined evaluable
predicates, like abs(Z) and sqrt(Z)
Modern Programming Languages
27
Real Values And Integers
?- X is
X = 0.5
Yes
?- X is
X = 0.5
Yes
?- X is
X = 2
Yes
?- X is
X = 2
Yes
1/2.
There are two numeric types:
integer and real.
1.0/2.0.
Most of the evaluable
predicates are overloaded for
all combinations.
2/1.
2.0/1.0.
Prolog is dynamically typed;
the types are used at runtime
to resolve the overloading.
But note that the goal 2=2.0
would fail.
Modern Programming Languages
28
Comparisons

Numeric comparison operators:
<, >, =<, >=, =:=, =\=
To solve a numeric comparison goal, Prolog
evaluates both sides and compares the
results numerically
 So both sides must be fully instantiated

Modern Programming Languages
29
Comparisons
?- 1+2 < 1*2.
No
?- 1<2.
Yes
?- 1+2>=1+3.
No
?- X is 1-3, Y is 0-2, X =:= Y.
X = -2
Y = -2
Yes
Modern Programming Languages
30
Equalities In Prolog

We have used three different but related
equality operators:
–
–
–

X
3
X
3
X
3
is Y evaluates Y and unifies the result with X:
is 1+2 succeeds, but 1+2 is 3 fails
= Y unifies X and Y, with no evaluation: both
= 1+2 and 1+2 = 3 fail
=:= Y evaluates both and compares: both
=:= 1+2 and 1+2 =:= 3 succeed
Any evaluated term must be fully instantiated
Modern Programming Languages
31
Example: mylength
mylength([],0).
mylength([_|Tail], Len) :mylength(Tail, TailLen),
Len is TailLen + 1.
?- mylength([a,b,c],X).
X = 3
Yes
?- mylength(X,3).
X = [_G266, _G269, _G272]
Yes
Modern Programming Languages
32
Counterexample: mylength
mylength([],0).
mylength([_|Tail], Len) :mylength(Tail, TailLen),
Len = TailLen + 1.
?- mylength([1,2,3,4,5],X).
X = 0+1+1+1+1+1
Yes
Modern Programming Languages
33
Example: sum
sum([],0).
sum([Head|Tail],X) :sum(Tail,TailSum),
X is Head + TailSum.
?- sum([1,2,3],X).
X = 6
Yes
?- sum([1,2.5,3],X).
X = 6.5
Yes
Modern Programming Languages
34
Example: gcd
gcd(X,Y,Z) :X =:= Y,
Z is X.
gcd(X,Y,Denom) :X < Y,
NewY is Y - X,
gcd(X,NewY,Denom).
gcd(X,Y,Denom) :X > Y,
NewX is X - Y,
gcd(NewX,Y,Denom).
Note: not just
gcd(X,X,X)
Modern Programming Languages
35
The gcd Predicate At Work
?- gcd(5,5,X).
X = 5
Yes
?- gcd(12,21,X).
X = 3
Yes
?- gcd(91,105,X).
X = 7
Yes
?- gcd(91,X,7).
ERROR: Arguments are not sufficiently instantiated
Modern Programming Languages
36
Example: factorial
factorial(X,1) :X =:= 1.
factorial(X,Fact) :X > 1,
NewX is X - 1,
factorial(NewX,NF),
Fact is X * NF.
?- factorial(5,X).
X = 120
Yes
?- factorial(20,X).
X = 2.4329e+018
Yes
?- factorial(-2,X).
No
Modern Programming Languages
37
Outline
20.6
 22.2
 22.3
 22.4

The Lighter Side of Prolog
Arithmetic in Prolog
Problem Space Search: 8 Queens
Farewell To Prolog
Modern Programming Languages
38
The 8-Queens Problem

Chess background:
–
–
–

Played on an 8-by-8 grid
Queen can move any number of spaces
vertically, horizontally or diagonally
Two queens are in check if they are in the same
row, column or diagonal, so that one could
move to the other’s square
The problem: place 8 queens on an empty
chess board so that no queen is in check
Modern Programming Languages
39
Representation
We could represent a queen in column 2,
row 5 with the term queen(2,5)
 But it will be more readable if we use
something more compact
 Since there will be no other pieces—no
pawn(X,Y) or king(X,Y)—we will just
use a term of the form X/Y
 (We won’t evaluate it as a quotient)

Modern Programming Languages
40
Example
8
7
Q
6
5
Q
4
3
2
Q
1
1
2
3
4
5
6
7
8
A chessboard configuration is just a list of
queens
 This one is [2/5,3/7,6/1]

Modern Programming Languages
41
/*
nocheck(X/Y,L) takes a queen X/Y and a list
of queens. We succeed if and only if the X/Y
queen holds none of the others in check.
*/
nocheck(_, []).
nocheck(X/Y, [X1/Y1 | Rest]) :X =\= X1,
Y =\= Y1,
abs(Y1-Y) =\= abs(X1-X),
nocheck(X/Y, Rest).
Modern Programming Languages
42
/*
legal(L) succeeds if L is a legal placement of
queens: all coordinates in range and no queen
in check.
*/
legal([]).
legal([X/Y | Rest]) :legal(Rest),
member(X,[1,2,3,4,5,6,7,8]),
member(Y,[1,2,3,4,5,6,7,8]),
nocheck(X/Y, Rest).
Modern Programming Languages
43
Adequate

This is already enough to solve the problem:
the query legal(X) will find all legal
configurations:
?- legal(X).
X = [] ;
X = [1/1] ;
X = [1/2] ;
X = [1/3]
Modern Programming Languages
44
8-Queens Solution
Of course that will take too long: it finds all
64 legal 1-queens solutions, then starts on
the 2-queens solutions, and so on
 To make it concentrate right away on
8-queens, we can give a different query:

?- X = [_,_,_,_,_,_,_,_], legal(X).
X = [8/4, 7/2, 6/7, 5/3, 4/6, 3/8, 2/5, 1/1]
Yes
Modern Programming Languages
45
Example
8
Q
7
Q
6
Q
5
Q
Q
4
Q
3
Q
2
1
Q
1
2
3
4
5
6
7
8
Our 8-queens solution
 [8/4, 7/2, 6/7, 5/3,
4/6, 3/8, 2/5, 1/1]

Modern Programming Languages
46
Room For Improvement
Slow
 Finds trivial permutations after the first:

?- X = [_,_,_,_,_,_,_,_], legal(X).
X = [8/4, 7/2, 6/7, 5/3, 4/6, 3/8, 2/5, 1/1] ;
X = [7/2, 8/4, 6/7, 5/3, 4/6, 3/8, 2/5, 1/1] ;
X = [8/4, 6/7, 7/2, 5/3, 4/6, 3/8, 2/5, 1/1] ;
X = [6/7, 8/4, 7/2, 5/3, 4/6, 3/8, 2/5, 1/1]
Modern Programming Languages
47
An Improvement
Clearly every solution has 1 queen in each
column
 So every solution can be written in a fixed
order, like this:

X=[1/_,2/_,3/_,4/_,5/_,6/_,7/_,8/_]

Starting with a goal term of that form will
restrict the search (speeding it up) and avoid
those trivial permutations
Modern Programming Languages
48
/*
eightqueens(X) succeeds if X is a legal
placement of eight queens, listed in order
of their X coordinates.
*/
eightqueens(X) :X = [1/_,2/_,3/_,4/_,5/_,6/_,7/_,8/_],
legal(X).
Modern Programming Languages
49
nocheck(_, []).
nocheck(X/Y, [X1/Y1 | Rest]) :% X =\= X1, assume the X's are distinct
Y =\= Y1,
abs(Y1-Y) =\= abs(X1-X),
nocheck(X/Y, Rest).
legal([]).
legal([X/Y | Rest]) :legal(Rest),
% member(X,[1,2,3,4,5,6,7,8]), assume X in range
member(Y,[1,2,3,4,5,6,7,8]),
nocheck(X/Y, Rest).

Since all X-coordinates are already known
to be in range and distinct, these can be
optimized a little
Modern Programming Languages
50
Improved 8-Queens Solution
Now much faster
 Does not bother with permutations

?- eightqueens(X).
X = [1/4, 2/2, 3/7, 4/3, 5/6, 6/8, 7/5, 8/1] ;
X = [1/5, 2/2, 3/4, 4/7, 5/3, 6/8, 7/6, 8/1] ;
Modern Programming Languages
51
An Experiment
legal([]).
legal([X/Y | Rest]) :legal(Rest),
% member(X,[1,2,3,4,5,6,7,8]), assume X in range
1=<Y, Y=<8, % was member(Y,[1,2,3,4,5,6,7,8]),
nocheck(X/Y, Rest).
Fails: “arguments not sufficiently
instantiated”
 The member condition does not just test
in-range coordinates; it generates them

Modern Programming Languages
52
Another Experiment
legal([]).
legal([X/Y | Rest]) :% member(X,[1,2,3,4,5,6,7,8]), assume X in range
member(Y,[1,2,3,4,5,6,7,8]),
nocheck(X/Y, Rest),
legal(Rest). % formerly the first condition
Fails: “arguments not sufficiently
instantiated”
 The legal(Rest) condition must come
first, because it generates the partial
solution tested by nocheck

Modern Programming Languages
53
Outline
20.6
 22.2
 22.3
 22.4

The Lighter Side of Prolog
Arithmetic in Prolog
Problem Space Search: 8 Queens
Farewell To Prolog
Modern Programming Languages
54
Parts We Skipped

The cut (!)
–
–

Exception handling
–
–

A goal that always succeeds, but only once
Used to control backtracking
System-generated or user-generated exceptions
throw and catch predicates
The API
–
–
A small ISO API; most systems provide more
Many public Prolog libraries: network and file
I/O, graphical user interfaces, etc.
Modern Programming Languages
55
A Small Language
We did not have to skip as much of Prolog
as we did of ML and Java
 Prolog is a small language
 Yet it is powerful and not easy to master
 The most important things we skipped are
the techniques Prolog programmers use to
get the most out of it

Modern Programming Languages
56