Sei sulla pagina 1di 3

Prolog programming exercises

Exercise 1 Starting with the "genealogy" code, define new predicates for "descendant", "sibling" and "uncle_or_aunt". Add some more "parent" facts to the collection (perhaps from your own relatives) and test out the predicates you introduced. Exercise 2 Does the following definition of ancestor allow queries which fail to terminate? (Note that the order of the two clauses has been reversed from the original definition). You can of course experiment with prolog to get an answer, but try to understand why, independently of experiment.
ancestor(X,Y):-parent(X,Z),ancestor(Z,Y). ancestor(X,Y):-parent(X,Y).

(Note: this is a "trick question") Exercise 3 Define a predicate subsequence(L1,L2) which is satisfied by any pair of lists L1 and L2 which have the property that the elements of L1 occur in order in L2, but are not necessarily consecutive. For example subsequence([tues,wed,sat], [mon,tues,wed,thurs,fri,sat,sun]) should be true, but subsequence([thurs,wed],[mon,tues,wed,thurs,fri,sat,sun]) should fail. Exercise 4 Define a predicate intersects(L1,L2) which is satisfied by lists L1 and L2 provided that they have an element in common. Exercise 5 Define a predicate bfora(L1,L2) which is satisfied by lists L1 and L2 provided that L2 is obtained from L1 by replacing all occurrences of a in L1 by b, including occurrences in sub-lists, sub-sub-lists and so on. (It might be useful to use the built-in predicate atom, which is satisfied by an argument consisting of an atom, but not by a more complicated term such as a list.)

Solutions to prolog exercises

Sample solutions to first set of cs205 logic programming exercises Solution 1


descendant(X,Y):-ancestor(Y,X). sibling(X,Y):-parent(Z,X), parent(Z,Y), X\==Y. % uncle_or_aunt(X,Y) will be defined % to mean that X is the uncle or aunt of Y uncle_or_aunt(X,Y):-parent(Z,Y),sibling(Z,X).

Solution 2 A query may fail to terminate if some parent relationships are given which are cyclic (hence could not arise in reality). For example
parent(bob,ann). parent(ann,gaz). parent(gaz,bob). parent(hal,betty).

The query ancestor(bob,hal) causes an infinite loop. (It's a trick question because the original definition of "ancestor" also fails in this situation. So in a sense this reversal of the clauses does not make the definition any worse.) Under "normal circumstances" queries will terminate. To see this, you have to appreciate how prolog ever gets to apply the second clause in the definition of ancestor. (Since the first is recursive, only the second can allow computation to end.) What happens is that given the query such as
ancestor(bob,X).

prolog will in fact find all the descendants of bob using the first clause, without ever using the second to verify that they are all bob's descendants. Eventually the first clause will start to fail - when bob's youngest descendants are reached they fail the first subgoal of being parents. At that point, prolog can start backtracking, giving up on the use of the first clause and trying out the second, and it will eventually do so for all descendants of bob. Solution 3
subsequence([],L). % the empty list is a subsequence of anything subsequence([Head|Tail],[Head|Tail2]) :- subsequence(Tail,Tail2). % if the two lists have the same leading element % then the first is a subsequence of the second % provided that the first without its leading element % is a subsequence of the second without that leading % element subsequence(L1,[Head|Tail]) :- subsequence(L1,Tail). % L1 is a subsequence of L2 if it is a subsequence % of L2 minus its leading element

Solution 4 It is easy to do this by defining an auxiliary predicate intersect2 which is satisfied by two lists if the head of the first list belongs to the second.

intersect2([Head|Tail1],[Head|Tail2]). intersect2([Head|Tail1],[Head2|Tail2]) :intersect2([Head|Tail1],Tail2). intersects([Head|Tail],L) :- intersect2([Head|Tail],L). intersects([Head|Tail],L) :- intersect2(Tail,L).

Solution 5

bfora([],[]). bfora(a,b). bfora(X,X) :- atom(X). bfora([H1|T1],[H2|T2]) :- bfora(H1,H2), bfora(T1,T2).

The predicate also replaces the atom a by b (as well as just working on the contents of lists). The second and third clauses deal with atoms in particular, replacing a with b, or failing that replacing an arbitrary atom by itself. Note that if you reject the answer to a query such as
bfora([[q,a,w],[a,q,a],q,a,e],L).

which initially gives


L = [[q,b,w],[b,q,b],q,b,e] ? then you get offered alternatives in which the last a may not have been replaced by b. This is due to using the third clause instead of the second (where the first argument is a, so that the second should have been used.)

Potrebbero piacerti anche