Pure Prolog vs. Extralogical Prolog COSC 2P93 : Extralogical Prolog • Pure Prolog programs can be interpreted as logical statements about what they compute. • they are self-describing! You can read them at a high-level. • term for such programs: declarative • (Well, this is an ideal... not always true!) • However, real-world requirements mean we have to use non-logical operations in Prolog programs in order for them to be practical. (a) input/output: reading from user, writing to screens, file I/O, ... (b) control: making execution more efficient (c) low-level operations: inspecting the construction of constants, structures,... (d) database operations: creating, deleting, altering program clauses (e) plus other advanced tools • Unfortunately, these practical needs usually have no direct logical meaning like pure Prolog programs. • Their inclusion therefore ruins our logical interpretation
*** Rule of Thumb *** COSC 2P93 : Extralogical Prolog • Use declarative predicates when they are practical. • Practical can mean... • It’s possible to do what is required. • Efficient (speed, resources). • Small programs.
listing, clause COSC 2P93 : Extralogical Prolog • After you consult your program file(s), the clauses are asserted into the program database. • To look at the clauses (*** after consult, not compile ***). (a) listing. - lists the whole program database (b) listing(functor/arity): lists one particular predicate • functor: predicate name • arity (optional): number of arguments • eg. listing(append/3). • listing(append). <-- acceptable if only one ‘append’ exists (c) clause(H, B): unifies H with a clause head, and B with its body • backtracking will let it unify with the next clause unifying with H and B • useful for grabbing clauses one after another
clause COSC 2P93 : Extralogical Prolog • (c) clause (cont) • eg. if our database has: member(X, [X|_]). member(X, [_|Y]) :- member(X, Y). ?- clause(X, Y). X = member(X,[X|_]) Y = true ; X = member(X,[_|Y]) Y= member(X,Y) ; no ?- clause(member(a,[a,b,c,d]), Y). Y = true ; Y = member(a, [b,c,d]). • facts are stored as: member(X,[X|_]) :- true. • true is a builtin that always succeeds (its definition: true. )
Assert, retract COSC 2P93 : Extralogical Prolog • (d) assert(X) : asserts the clause X into the program database asserta(X): asserts clause X as the first clause in its predicate assertz(X): asserts clause X as the lasst clause in its predicate • eg. if program is: parent(tom, bob). parent(mary, bob). ?- asserta(parent(kim, nixon)). yes. ?- assertz(parent(X,Y) :- father(X.Y)). yes. ?- listing(parent). parent(kim, nixon). parent(tom, bob). parent(mary, bob). parent(X,Y) :- father(X,Y).
Assert, retract COSC 2P93 : Extralogical Prolog • (e) retract(X): finds first clause that unifies with X, and removes it ?- retract(parent(mary,X)), X = bob <-- note that it shows result of unification ?- listing(parent). parent(kim, nixon). parent(tom, bob). parent(X,Y) :- father(X,Y). • (f) abolish(functor/arity): removes entire predicate ?- abolish(parent/2). yes ?- listing(parent). yes • using assert and retract, you can create & assert new facts and rules in your program, which can be executed as normal Prolog clauses
Assert, Retract COSC 2P93 : Extralogical Prolog eg. create a list of numbers from 1 to N, and assert that list for use later make_num_list(N) :- make_list(N, List), asserta(my_list(List)). make_list(N, [ ]) :- N =< 0. make_list(N, [N | Rest]) :- N > 0, N2 is N - 1, make_list(N2, Rest). • Thereafter, there exists a fact: my_list([1,2,3,... ] ): ?- make_num_list(10), my_list(L). L=[1,2,3,4,5,6,7,8,9,10]
Assert/Retract COSC 2P93 : Extralogical Prolog • Consider the following: ?- make_num_list(12). yes ?- listing(my_list). my_list([1,2,3,4,5,6,7,8,9,10,11,12]). yes ?- make_num_list(8). yes ?- listing(my_list). my_list([1,2,3,4,5,6,7,8]). my_list([1,2,3,4,5,6,7,8,9,10,11,12]). • If we only want one my_list, we need to remove the previous one: make_num_list(N) :- abolish(my_list/1), % always succeeds, even if my_list doesn’t exist make_list(N, List), asserta(my_list(List)).
Warning about assert & retract“Danger! Danger Will Robinson!” COSC 2P93 : Extralogical Prolog • You need to be disciplined when you use assert and retract • you should neveruse it as a regular means to pass data among predicates • eg. in the last example, we could just as easily create the list and pass it to other predicates... • ?- make_list(N,L), do_something(L), do_something_else(L), ... • often assert & retract are used for very large data items which are ‘global’ in nature, and in which passing the data is too inconvenient • assert & retract are side effects! • side effect: with respect to Prolog, any activity other than unifying logical variables • when you call make_num_list, a side effect is the creation of a new fact. • There is no way to know make_num_list will do this from looking at its arguments; you must look at its code in detail to know this • Very bad effect on program clarity, declarativity, etc
Prolog Input & Output COSC 2P93 : Extralogical Prolog • Writing terms: write(X) - writes the term X to screen upon backtracking, write will fail nl - write a newline eg. simple debugging: make_list(N, [ ]) :- N =< 0, write(first),write(N),nl. make_list(N, [N | Rest]) :- N > 0, write(second), write(N), N2 is N - 1, make_list(N2, Rest), write(second),write(‘finished make_list!’),nl. • Note: ‘finish make_list!’ is one constant; need single quotes!
I/O COSC 2P93 : Extralogical Prolog • eg. write out all the parent clauses to the screen write_parent :- clause(parent(X,Y), B), write(parent(X,Y)), write(‘:-’), write(B), write(‘.’), nl, fail. write_parent. % when clause above finally finishes, this will let write_parent % gracefully succeed (rather than fail) • This is a failure-driven loop. • fail: always fails! (a builtin clause that isn’t defined anywhere) • Improvements we can make: 1. facts are printed strangely: parent(bob, bill) :- true. 2. tedious to write things term by term 3. would be nice to make this more general, and not specific to parent
Improved write_clauses COSC 2P93 : Extralogical Prolog ?- dynamic write_list/1. % to use as example clause write_clauses(P) :- clause(P, B), write_one_clause(P,B), fail. write_clauses(_). write_one_clause(P, true) :- write_list([P, '.', nl]). write_one_clause(P, B) :- \+ (B == true), write_list([P, ':-', nl, tab(5), B, '.', nl]). write_list(). write_list([nl|R]) :- nl, write_list(R). write_list([tab(N)|R]) :- tab(N), write_list(R). write_list([T|R]) :- \+ (T=nl; T=tab(_)), write(T), write_list(R).
tab COSC 2P93 : Extralogical Prolog tab(0). tab(K) :- K > 0, write(' '), K2 is K-1, tab(K2).
Other I/O COSC 2P93 : Extralogical Prolog • read(X) - reads next term from input stream • input terminated by ‘.’ • fails upon backtracking • Prolog will try to unify user input with read argument; eg. p(X) :- write(“What is your name?”), read(X). • get(X) - read a single character put(X) - write a single character ...plus many more
File I/O COSC 2P93 : Extralogical Prolog see (X) - opens input stream to come from file ‘X’ • error if X uninstantiated, or file X doesn’t exist • default: ‘user’ (terminal keyboard, standard input) seeing(X) - indicates where you are currently reading input from seen - closes input stream, resets input as ‘user’ tell(X) - opens file X as target for output stream • default: ‘user’ telling(X) - where you are writing to told - closes output stream, resets to ‘user’
Example file I/O COSC 2P93 : Extralogical Prolog % write_to_file(File, List): writes entire List to File, one line per entry write_to_file(File, List) :- telling(Old), % save old output stream name tell(File), % open new output stream dump_list(List), told, tell(Old). % this resets output to previous destination write_to_file(File, _) :- write(‘unable to write to file ‘), write(File). dump_list([ ]). dump_list([X| T]) :- write(X), nl, dump_list(T).