150 likes | 268 Views
Programming Style and Technique. Notes for Ch. 8 of Bratko For C ENG421&553 Fall 03. Use. Use of Recursion: maplist. Recursion is always used. maplist is an example of a “higher-order function”: a function that applies to another function In the original LISP (McCarthy, 1960):
E N D
Programming Style and Technique Notes for Ch.8 of Bratko For CENG421&553Fall03
Use of Recursion: maplist • Recursion is always used. maplist is an example of a “higher-order function”: a function that applies to another function • In the original LISP (McCarthy, 1960): • ((label maplist (lambda (x f) (cond ((null x) ‘( )) (‘t (cons (f (car x)) (maplist (cdr x) f)))))) • maplist( List, F, NewList) if NewList contains the result of applying F to each element of List, in order • The function F the binary relation representing the function we want to apply
maplist II • Boundary (base) case: List = [ ] • if List = [ ] then NewList = [ ] • General case: List = [ X|Tail] • To transform a list of the form [ X|Tail], do • transform the item X by F, obtaining New X, and • transform the list Tail obtaining NewTail • the whole transformed list if [ NewX|NewTail] • See ch8_1.pl • Prolog recursion objects recursive
/* maplist( List,F,NewList) if NewList contains the result of applying the function F (represented by a binary relation <domain,range>) to each entry of NewList, in order. */ maplist( [],_,[]). maplist( [ X|Tail],F,[ NewX|NewTail]) :- G =.. [ F,X,NewX], G, % some Prologs require call( G) instead of G maplist( Tail,F,NewTail). /* Square function, for example query ?- maplist( [2,6,5],square,Squares) */ square( X,Y) :- Y is X*X.
Generalization • Generalization allows us to use recursion • Example: eight queens • without generalization, no integer to recur on! • Define nqueens( Pos,N) • if N queens are safe in position Pos • Base case: N = 0: trivial • General case: N > 0 • achieve a safe configuration of N-1 queens • add the remaining queen so that it does attack • eightqueens( Pos) :- nqueens( Pos,8).
Debugging • Most Prolog interpreters and compilers use a four-port model for goals call foo/n succeed fail retry
Improving Efficiency • Eight queens, again: • using a more informed initial ordering of queen coordinate values helps, as described in the comments at the end of ex4_6.pl • Map coloring • start with countries that have many neighbors • Warnsdorff’s heuristic for the knight’s tour
% Ex 4.6[B] % Figure 4.7 Program 1 for the eight queens problem. % solution( BoardPosition) if % BoardPosition is a list of non-attacking queens solution( [] ). solution( [X/Y | Others] ) :- % First queen at X/Y, other queens at Others solution( Others), member( Y,[1,2,3,4,5,6,7,8]), % Order of alternatives defined here! noattack( X/Y, Others). % First queen does not attack others noattack( _, [] ). % Nothing to attack noattack( X/Y, [X1/Y1 | Others] ) :- Y =\= Y1, % Different Y-coordinates Y1-Y =\= X1-X, % Different diagonals Y1-Y =\= X-X1, noattack( X/Y, Others). % A solution template template( [1/Y1,2/Y2,3/Y3,4/Y4,5/Y5,6/Y6,7/Y7,8/Y8] ). solution1(S) :- template(S), solution(S). % When computing all solutions, all orders are equivalent: /* Original Order: member( Y,[1,2,3,4,5,6,7,8]) 4 ?- time(setof(S,solution1(S),L)), length(L,N). % 171,051 inferences in 0.22 seconds (776387 Lips) */ /* More informed order: member( Y,[1,3,5,7,2,4,6,1]) 16 ?- time(setof(S,solution1(S),L)), length(L,N). % 171,051 inferences in 0.22 seconds (776387 Lips) */ % When computing one solution, the informed order is much better: /* More informed order: member( Y,[1,3,5,7,2,4,6,1]) 18 ?- time(solution1(S)). % 368 inferences in 0.00 seconds (Infinite Lips) */ /* Original Order: member( Y,[1,2,3,4,5,6,7,8]) 19 ?- time(solution1(S)). % 9,382 inferences in 0.01 seconds (936851 Lips) */
colors( []). colors( [ Country/Color|Rest]) :- colors( Rest), member( Color,[yellow,blue,red,green]), not( (member( Country1/Color,Rest),neighbor( Country,Country1)) ). % Note the extra parentheses, to make a single conjunctive goal of two neighbor( Country,Country1) :- ngb( Country,Neighbors), member( Country1,Neighbors). makelist( List) :- collect( [germany],[],List). collect( [],Closed,Closed). % No more candidates for closed collect( [ X|Open],Closed,List) :- member( X,Closed),!, % If X has already been collected, collect( Open,Closed,List). % discard it collect( [X|Open],Closed,List) :- ngb( X,Ngbs), conc( Ngbs,Open,Open1), % built-in version of concat collect( Open1,[ X|Closed],List). country( X) :- ngb( X,_). % Incomplete ngb relation below gives only six countries
% Neighbors for the 6 original EU countries (Treaty of Rome, 1957) % Andorra, Monaco, San Marino, and Vatican City are not considered % Only land (bridge and tunnel included) borders are considered /* Reorder the ngb relation so that the country that has the largest amount of neighbour will be at the top. So start coloring from that, continue with its neighbours, then the neighbours of the neighbours etc. */ ngb( germany, [denmark,poland,czech,austria,switzerland,france,luxembourg,belgium,netherlands]). ngb( netherlands, [germany,belgium,france]). ngb( belgium, [netherlands,germany,luxembourg,france]). ngb( france, [belgium,luxembourg,germany,switzerland,italy,spain]). ngb( luxembourg, [belgium,germany,france]). ngb( italy, [france,austria,slovenia]). ngb( denmark, [germany]). ngb( poland, [germany]). ngb( czech, [germany]). ngb( austria, [germany, italy]). ngb( switzerland, [germany,italy,france]). ngb( spain, [france]). ngb( slovenia, [italy]).
Difference Lists • The difference list L-E contains the elements of L that occur before E. E is a suffix of L. • E.g., [a,b,c,d] – [c,d] is [a,b] • Trick: [a,b,c,d|E] – E is [a,b,c,d]! • Difference lists allow concatenation of lists in constant time, as in imperative languages.
Concatenation and Difference Lists • Difference lists can be concatenated in constant time by using conc_dl: • ?conc_dl([a,b|A] – A, [c,d|C] – C, Result) unify with conc_dl(X – Y, Y – Z, X – Z): • {X / [a,b|A]} • {Y / A} • {A / [c,d|C]} • {Z / C} • {Result / X – Z}, i.e. {Result / [a,b|A] – C}, i.e. • {Result / [a,b,c,d|C} – C}
Some Caveats • While the result of conc_dl has an uninstatiated tail, the first argument does not. • You cannot use it as an argument to conc_dl in the same clause. • “Difference lists are powerful but counterintuitive. They appear most often in procedures that were first implemented with conventional lists and then carefully rewritten for efficiency” [Covington, p.183].
Improveing efficiency by asserting derived facts • fib and fib2. • Execution trees • Page 204 • More difficult but more efficient one:forwardfib