Learning Prolog: Lab #9
Sorry this post is rather late! I had multiple ACW deadlies to deal with, and I now have a nasty cold as of the time of writing :(
I had a bit of trouble with this lab - I originally lost the code that I had written due to a bug in my chromebook where it doesn't resume properly when I lift the lid...! Anyway, the main point of this lab was to practice the Prolog that we have learnt already. A lot. There were 7 problems to solve, 6 of which I have a solution for. The first two aren't very interesting, so I'll just include the code and some examples below and move on.
sbrlmember(Item, [ Head | Tail ]) :-
Item = Head ;
sbrlmember(Item, Tail).
lastitem([ LastItem | [] ], LastItem).
lastitem([ _ | Tail ], LastItem) :-
lastitem(Tail, LastItem).
?- sbrlmember(Item, [ apple, orange, grape ]).
Item = apple ;
Item = orange ;
Item = grape ;
false.
?- lastitem([ car, bus, truck, lorry, aeroplane ], Result).
Result = aeroplane .
The above contains definitions for two rules: sbrlmember
and lastitem
.
sbrlmember
works exactly like the member
function that's built into
Prolog, and lastitem
, given a list, tells you what the last item in that
list is.
The next one in the sequence is a rule that, given a list, returns the reverse of that list. Here's my solution, and an example:
listreverse([ Head | [] ], [Head]).
listreverse([ Head | Tail ], Result) :-
listreverse(Tail, TailReversed),
append(TailReversed, [Head], Result).
?- listreverse([windows, max, linux], Result).
Result = [linux, max, windows] .
Basically, it recurses over the tail of the list until there is just a single item left, at which point it returns the head on it's own in a list. When it comes back out of the recursion, it sticks everything back on the end of the list again in the reverse order.
The next problem we were given was to, given a pair of lists, return a third list containing all the items that appeared in both of the original lists. I decided to cheat a bit here and use an accumulator
intersection([], _, []).
intersection([ Head | Tail ], ListB, Result) :-
member(Head, ListB),
intersection(Tail, ListB, RecResult),
append(RecResult, [Head], Result).
intersection([ _ | Tail ], ListB, Result) :-
intersection(Tail, ListB, Result).
Complicated problems call for complicated solutions, so I decided to recurse over the first list and check to see if the current item is present in the second list. If so, then we add it to the result - if not, then we simply ignore it and carry on recursing. When it hits the end o fthe recursion, I start it off with an empty list, which it then adds to as it climbs its way back out of the recursion.
?- intersection([snow, rain, wind, flame], [snow, flame], Result).
Result = [flame, snow] .
The last problem I built a solution for asked for a rule that deleted the given atom (I think that's what you call them in Prolog?) from the given list.
deleteall(_, [], []).
deleteall(Item, [ Head | Tail ], [ Head | Result ]) :-
not(Item = Head),
deleteall(Item, Tail, Result).
deleteall(Item, [ _ | Tail ], Result) :-
deleteall(Item, Tail, Result).
?- deleteall(snake, [ squirrel, bird, cat, snake ], Result).
Result = [squirrel, bird, cat] .
My solution copies everything in the list over to the result (rather like the intersection problem above actually), unless the next item along is equal to the item we are supposed to be ognoring, in which case we skip it. I do this by adding a condition on the rule that copies the item over to the result that it can't be the item that we were told to remove.
That's the last problem from this lab - I'll have the solutions for the 10th lab up soon.