580 likes | 799 Views
Prolog Tricks. Outline. 20.6 The Lighter Side of Prolog 22.2 Arithmetic in Prolog 22.3 Problem Space Search: 8 Queens 22.4 Farewell To Prolog. Quoted Atoms As Strings. Any string of characters enclosed in single quotes is a term In fact, Prolog treats it as an atom:
E N D
Prolog Tricks Modern Programming Languages
Outline • 20.6 The Lighter Side of Prolog • 22.2 Arithmetic in Prolog • 22.3 Problem Space Search: 8 Queens • 22.4 Farewell To Prolog Modern Programming Languages
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
Input and Output ?- write('Hello world'). Hello worldYes?- read(X).| hello.X = hello Yes • Simple term input and output. • Also the predicate nl: equivalent to write('\n') Modern Programming Languages
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
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
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
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
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
/* 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
/* report prints the description of your current location.*/report :- at(you,X), description(X,Y), write(Y), nl. Modern Programming Languages
?- 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
/* 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
/* 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
/* Shorthand for moves.*/forward :- move(forward).left :- move(left).right :- move(right). Modern Programming Languages
?- 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
/* 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
/* 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
/* 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
/* 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, cliff, main. The predefined predicate call(X) tries to prove X as a goal term. Modern Programming Languages
/* 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
?- 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
Outline • 20.6 The Lighter Side of Prolog • 22.2 Arithmetic in Prolog • 22.3 Problem Space Search: 8 Queens • 22.4 Farewell To Prolog Modern Programming Languages
Unevaluated Terms • Prolog operators allow terms to be written more concisely, but are not evaluated • These are all the same Prolog term: • That term does not unify with 7 +(1,*(2,3))1+ *(2,3)+(1,2*3)(1+(2*3))1+2*3 Modern Programming Languages
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
Instantiation Is Required ?- Y=X+2, X=1.Y = 1+2X = 1 Yes?- Y is X+2, X=1.ERROR: Arguments are not sufficiently instantiated?- X=1, Y is X+2.X = 1Y = 3 Yes Modern Programming Languages
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
Real Values And Integers ?-X is 1/2.X = 0.5 Yes?- X is 1.0/2.0.X = 0.5 Yes?- X is 2/1.X = 2 Yes?-X is 2.0/1.0.X = 2Yes There are two numeric types: integer and real. Most of the evaluable predicates are overloaded for all combinations. 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
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
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 = -2Y = -2 Yes Modern Programming Languages
Equalities In Prolog • We have used three different but related equality operators: • X is Y evaluates Y and unifies the result with X: 3 is 1+2 succeeds, but 1+2 is 3 fails • X = Y unifies X and Y, with no evaluation: both 3 = 1+2 and 1+2 = 3 fail • X =:= Y evaluates both and compares: both 3 =:= 1+2 and 1+2 =:= 3 succeed • Any evaluated term must be fully instantiated Modern Programming Languages
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
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
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.5Yes Modern Programming Languages
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
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
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
Outline • 20.6 The Lighter Side of Prolog • 22.2 Arithmetic in Prolog • 22.3 Problem Space Search: 8 Queens • 22.4 Farewell To Prolog Modern Programming Languages
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
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
Example • A chessboard configuration is just a list of queens • This one is [2/5,3/7,6/1] Modern Programming Languages
/* 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
/* 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
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
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
Example • Our 8-queens solution • [8/4, 7/2, 6/7, 5/3, 4/6, 3/8, 2/5, 1/1] Modern Programming Languages
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
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
/* 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
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