250 likes | 507 Views
8. Higher Order Predicates. Higher order predicates in PROLOG. Higher order declarative predicates : findall bagof setof =.. Higher order non-declarative predicates : call . asserta , assertz . retract . Higher Order Predicates in PROLOG. PROLOG implements a subset of classical logic.
E N D
8. Higher Order Predicates • Higher order predicates in PROLOG. • Higher order declarative predicates : • findall • bagof • setof • =.. • Higher order non-declarative predicates : • call. • asserta, assertz. • retract.
Higher Order Predicates in PROLOG • PROLOG implements a subset of classical logic. • Horn Clause Predicate Calculus. • Can only write facts and rules about terms. • Cannot have facts and rules about predicates. • PROLOG also provides a set of predicates which operate on other predicates : higher order predicates. • Some are declarative : • findall, bagof, setof, =... • Some are not : • call, asserta, assertz, retract.
Back To The Romans • Suppose we have the following database : consul(metellus, 80). consul(sulla, 80). consul(cicero, 63). consul(antonius, 63). consul(caesar, 59). consul(bibulus, 59). consul(pompeius, 55). consul(crassus, 55). consul(ahenobarabus,54). consul(pulcher, 54). consul(pompeius, 52). consul(metellus, 52). consul(caesar, 48). consul(servilius,48). consul(caesar, 46). consul(lepidus, 46). consul(caesar, 45). consul(caesar, 44). consul(antonius, 44). consul(pansa, 43). consul(octavius, 43). • Some of the Consuls of the late Roman republic. • Supposed to be two each year. • Julius Caesar was sole Consul in 45BC. • Julius Caesar was an unusual man.
Finding Consuls • Easy to write queries about Consuls : | ?- consul(C, _). C = metellus ; C = sulla ; C = cicero yes | ?- consul(C, 59). C = caesar ; C = bibulus ; no | ?- • By using ; to force backtracking we can find all the Consuls in the database. • A bit tedious. More convenient to have PROLOG give us all the answers at once in a list structure.
Using findall • The higher order predicate findall allows us to get all the answers at once. | ?- findall(C, consul(C, _), L). L = [metellus, ..., octavius] | ?- findall(C, consul(C, 59), L). L = [caesar, bibulus] yes | ?- • Instantiate L to be the list of all values of C for which the query (the second parameter of findall) is true. If there are no such values then instantiate L to be the empty list.
findall More Formally • In general findall(Term[V], Query[V], L). means instantiate L to be the list of values of Term[V] for which the query Query[V] is true. If there are no such values then L is instantiated to []. • Term[V] is an arbitrary term containing the logical variable V. • Query[V] is an arbitrary query containing the logical variable V. | ?- findall([C,was,in,59,bc],consul(C,59),L). L = [[caesar,was,in,59,bc], [bibulus,was,in,59,bc]] yes | ?-
findall More Formally II • Term[V] is the selector term. • Query[V] is the generator query. • L is the result list. • The selector term is often just a single logical variable but it can be any term. • The variable in the selector does not have to appear in the generator. • Not much point doing that though. The results are (usually) not useful. • Using GNU PROLOG : | ?- findall(X,consul(C,_),L). L = [_,_, ... ,_] | ?-
bagof and setof • findall is actually a generalisation of two other higher-order predicates : bagof and setof. | ?- bagof(W, consul(caesar, W), L). W = [59,48,46,45,44] | ?- setof(W, consul(caesar, W), L). W = [44,45,46,48,59] | ?- bagof(C, consul(C, _), L). L = [pansa,octavius] ? ; L = [caesar,antonius] ? yes | ?- setof(C, consul(C, _), L). L = [octavius,pansa] ? ; L = [antonius,caesar] ? yes | ?- • _ does not work properly with bagof or setof.
The All Values Construct • bagof and setof produce a separate solution for each of the different values of the second argument to consul even if the second argument is _. • To make bagof and setof collect all the values regardless of the values of the parameters not mentioned in the selector term we must use ^. | ?- bagof(C,When^consul(C,When),L). L = [metellus, ..., octavius] yes | ?- setof(C,When^consul(C,When),L). L = [ahenobarabus, ..., sulla] yes | ?- • setof produces its results in < order and with duplicates removed.
Sets vs. Bags • Using bagof the same answer may appear several times in the result list. • e.g. Caesar was Consul several times. • A bag is a mathematical concept meaning a collection of things. • A set is a mathematical concept meaning a collection of things without duplicates. • In mathematics a set is unordered. • In PROLOG setof always orders its results since this makes removing duplicates easier. • The ordering is almost always the ordering you would expect. • Numerical for numbers. • Lexicographical for alphanumerics.
setof, bagof and findall • If there are no values for which the generator term succeeds then findall succeeds and binds the result list to []. • setof and bagof will fail in this case. | ?- findall(C,consul(C,79),L). L = [] yes | ?- bagof(C,consul(C,79),L). no | ?- setof(C,consul(C,79),L). no | ?-
setof, bagof and findall II • findall, bagof and setof will not work if the generator query is a logical variable. • PROLOG cannot perform higher order matching. • findall, bagof and setof are functional rather than relational. • Still declarative though. | ?- findall(1, Q, [1]). uncaught exception : ... | ?- • findall, bagof and setof are similar to the list comprehension operators found in functional programming languages.
Making Structures From Lists | ?- T =.. [consul, X, Y]. T = consul(X, Y). yes | ?- • =.. converts its right hand argument from a list into a structure. • The first element is used as the functor. • The rest of the elements are the components. • The structure is then matched with the left hand argument. • =.. is declarative (but not relational). However, it is often used with call which is not declarative.
Making Goals From Lists | ?- T =.. [consul, X, Y], call(T). T = consul(metellus, 80) X = metellus Y = 80 ; T = consul(sulla, 80) X = sulla Y = 80 yes | ?- • The argument of call can be any structure. call treats the structure as a goal (i.e. a query) and solves it. • Seems a lot of trouble to go to just to solve consul(X, Y). • The pay off is that we can use =.. and call to evaluate any arbitrary list as a goal. • e.g. a list generated by a previous goal. • We can generate goals to solve as the program runs.
Making Goals From Lists II • In effect, we can write programs that compute goals for themselves as they go on. • Very useful in AI where programs must exhibit adaptive behaviour. • This can make debugging somewhat difficult : a program could produce incorrect results, or even crash, by attempting to solve a goal which did not exist in the text of the program when it was written. • To make debugging even more fun PROLOG allows programs to actually add and remove predicates as they run by using the asserta, assertz and retract higher order predicates.
asserting Facts | ?- move(A, B). uncaught exception : ... | ?- assertz(move(newcastle, durham)). yes | ?- move(A, B). A = newcastle B = durham ; no | ?- assertz(move(durham, sunderland)). yes | ?- move(A,B). A = newcastle B = durham ; A = durham B = sunderland ; no | ?-
asserting Facts II • Initially there are no predicates about move in the database so the query causes an exception. • We then use assertz to add the clause move(newcastle,durham) to the end of the database. The query now succeeds once. • We then use assertz to add the clause move(durham, sunderland) to the end of the database. The query now succeeds twice. • The two new facts are added to the database held within GNU PROLOG. • The copy on disk is unaffected. • In contrast, call does not modify the database. It throws away the goal once it has been solved.
asserting Rules | ?- assertz((move(X,Y):-move(X,Z),move(Z,Y))). yes | ?- move(A, B). A = newcastle B = durham ; A = durham B = sunderland ; A = newcastle B = sunderland ; yes | ?- • Note that an extra pair of brackets are required when asserting a rule. • asserted rules can be very memory hungry in some PROLOG systems (for example, in GNU PROLOG).
retracting Predicates • Predicates can be removed from the database using retract. | ?- retract((move(X,Y):-move(X,Z),move(Z,Y))). yes | ?- move(A, B). A = newcastle B = durham ; A = durham B = sunderland yes | ?- • Note that an extra pair of brackets are required when retracting a rule. • To retract a fact or rule it must be listed in full.
retracting Predicates II | ?- retract((move(durham,sunderland))). yes | ?- move(A, B). A = newcastle B = durham yes | ?- retract((consul(pansa,43)). uncaught exception : ... | ?- • GNU PROLOG only lets us retract predicates which we have asserted at run time. Some PROLOGs will allow predicates from the original database to be retracted as well. • retract doesn’t affect the program on disk.
Using =.. With assert And retract • Can use =.. to convert an arbitrary (i.e. program generated) list into a structure and then either assert or retract it. | ?- T =.. [move,london,newcastle], assertz(T). T = move(london,newcastle) yes | ?- move(A, B). A = newcastle B = durham ; A = london B = newcastle yes | ?- T =.. [move,newcastle,durham], retract(T). T = move(newcastle,durham) yes | ?- move(A, B). A = london B = newcastle yes | ?-
Self Modifying Code : Advantages • Using =.., asserta, assertz and retract we can write self modifying code. • Code that changes its behaviour as it runs. • This is very useful for AI systems as it supports adaptive behaviour. • A similar facility is provided in LISP via the eval ‘function’. • asserta, assertz and retract can be used in the same way as any other predicate. • In particular, you can put calls to them in the rules in your program. • Very flexible. • Very powerful.
Self Modifying Code : Disadvantages • call is bad enough for debugging : a bug can be caused by a call of a goal which is not in the original program. • asserta, assertz and retract are even worse. • A bug can be caused by a fact or a rule which does not exist in the original program but which was asserted at run time. • With some PROLOG systems, a bug can be caused by a call of a fact or a rule which does exist in the original program but which was retracted at run time. • asserta, assertz and retract are less declarative than the C++ goto statement. • asserta, assertz, retract, =.. and call are extremely powerful constructs. They should be used with caution. • Caution = Don’t use them unless you have to.
Summary • findall, bagof and setof return all the successful answers for a query. findall(Term[V], Query[V], L) • Term[V] is the selector term. • Query[V] is the generator query. • L is the result list. • bagof and setof have the same argument format as findall. • setof orders its results and removes duplicates. findall and bagof do not. • _ doesn’t work properly with setof and bagof. Must use the all values construct.
Summary II • =.., call, asserta, assertz and retract allow us to write self modifying code. • =.. converts its list argument into a structure. • call treats its structure argument as a goal and solves it. • asserta treats its structure argument as a clause and adds it to the start of the database. • assertz treats its structure argument as a clause and adds it to the end of the database. • retract treats its structure argument as a clause and removes it from the database. • Using GNU PROLOG we can only retract clauses asserted at run time. • Self modifying code is dangerous.