EXERCISE SHEET 4 {This time we have a pot pourri of things for you to try out, starting with arithmetic. Type in the following queries, and see if you can anticipate what Prolog will respond:} X is 12-4/4. X = 12-4, Y is X/4. 7*3 = 3*7. 7*3 =:= 3*7. 2+8 >= 12-2. {Try the following two, they show you how to use "less than or equal to" in SICStus prolog.} Y is 3*(8-2), Y-3 <= Y-2. Y is 3*(8-2), Y-3 =< Y-2. {Here's a little function, see if you can figure out what it does:} [user]. c(_, [], 0). c(X, [X|L], N):- c(X, L, R), !, N is R+1. c(X, [_|L], N):- c(X, L, N). ^D {If you don't know what it would do, try it out on these examples. What will happen if you hit a ; after the "N = blah" question?} c(4, [2,3,4,3,4,5,4,5,6], N). c(1, [2,3,4,5], N). c(X, [2,3,4,5], K). {Now for a quick look at assert and retract.} do(1). assert(do(1)). do(1). asserta(do(2)). assertz(do(3)). {Use ;'s in this next bit to see the order in which X is instantiated.} do(X). assert(do(4)). do(X). {Keep using ;'s here, and retract all do(_)'s.} retract(do(X)). do(X). {Let's add a few more things to the database, then play with them...} assert(p(a)), assert(p(b)), assert(p(c)). p(X), write(X), fail. retract(p(b)). p(X), write(X), fail. retract(p(X)), write(X), fail. p(S). {That'll do for that, we'll look at the -> operator now. Assume that you make this query: ?- p -> q; r. If p is true, then it will go to q. But if q is not true, it will not backtrack through "->". It will fail the whole query. In other words, if both p and q are true, this query will be answered with yes. If p is false and r is true, Prolog will answer yes as well. In all other cases (i.e. when (1) p is true and q is false; or (2) r is false) the query will fail. } assert(t(v)). t(v) -> write(aye) ; write(nay). t(x) -> write(aye) ; write(nay). t(x) -> write(aye) ; write(nay), fail. t(v) -> write(aye), fail ; write(nay), fail. t(v) -> write(aye), fail ; write(nay). {These next two show you why you need the brackets...} t(x), (t(v) -> write(aye) ; write(nay)). t(x), t(v) -> write(aye) ; write(nay). {You may ask, what is the difference between the following two goals? t(x) -> q; r t(x), !, q; r Well, the following example programs will show you the answer, but before you read on, try to figure it out yourself.} [user]. p1 :- t(v) -> fail; write('reach end of 1st clause'). p1 :- write('reach second clause'). p2 :- t(v), !, fail; write('reach end of 1st clause'). p2 :- write('reach second clause'). ^D {Then try to call both p1 and p2 and see the difference. The point is: backtracking through "!" fails the whole predicate call while backtracking through "->" will only fail that particular clause.} {A little now on true & fail.} (t(x) -> write(aye) ; true), write(end). (t(v) -> write(aye) ; true), write(end). true -> write(aye) ; write(nay). fail -> write(aye) ; write(nay). {For this next part of the exercise, you'll need the program 'cards'} {This is supposed to make your brain reel with !'s... Let's try it out, first. What do you think this line will do?} suit(S), !, rank(R), write(R of S), nl, fail. {Let's see something similar by calling the cards predicate.} cards. {If you look at the copy of this program which I've given you, you'll see a few comments, namely % 1, % 2, % 3 and % 4. Leave Prolog and edit the cards program using VI ou emacs ou textedit:} halt. vi cards {From within VI, put a cut just before the % of % 1. Make sure you put a comma after it, or it'll be illegal syntax. So that line should end in "!, % 1" now (without the quotes). Leave VI and get back to Prolog. Once in Prolog, read in the file 'cards' again. It'll be your edited version. If you get a syntax mistake, leave Prolog and fix it in VI, then get back to Prolog again and re-read it in. Now retry the 'cards' function again. What happens?} cards. {Now you've seen the effect of a ! at % 1, get back to VI and take it out. Put another at % 2 and see what that does. Repeat the process for % 3.} {We leave the predicate 'cards' now for a while, and look at some of the other functions, which have been declared as infix operators just to confuse you yet more!} 6 above X. X above Y. X above ace. X above 4. {That gives you the basic idea of 'above'. Now let's see 'beats'. Answer the "X = blah" with a ;.} jack beats X. {You'll see that the definition of 'beats' has % 4 to % 8 in it. Put a ! in each of these places, one at a time, and see what effect this has on the output. Yes, I know it's tedious doing this, but !'s ARE important! Try them out on:} jack beats X. {Now you have an idea of what 'beats' does, take out all the !'s again and see if you can figure out how this next little beastie performs its tricks:} jack beatsall [2,4,3,7]. jack beatsall [2,6,queen,9]. {There's a final function, 'go', which does all sorts. First, let's see its effects:} go. {Now it's back to VI for cuts at % 10 to % 14. What effects do these have on the output? Just put one ! in at a time, remember, I don't want to cause you any more distress than is necessary! If you don't follow what happens, use tracing, that might help.} {Here is a definition of a predicate 'picture'. It's dead easy, as kings, queens and jacks are pictures automatically, and nothing else is...} [user]. picture(king). picture(queen). picture(jack). ^D {Write a version called 'nopicture', where nopicture(X) succeeds if X is not a picture. Oh, and you're not allowed to use the function '\+'...} {OK, back to 'cards' for a moment. Edit the 'cards' function itself so that it has no !'s, and the write and nl are replaced by assert(R of S). Then return to Prolog and read it in. What will happen when you call the function?} cards. {By asking a few queries of your own devising, see if your guess was correct. What will this next line do?} retract(R of spades), fail. {If you don't know, have a look by typing:} listing(of). {See if you can type another line to put all of them back again... Then, that's it!}