Lecture 5 Accumulating results Contents • Three ways of computing results during re- cursion
Collecting results during recursion • Compute lower result, then use it at this level • Pass down accumulating value, finalise at base • Recurse on uninstantiated nested value 2 “Introduction to Artificial Intelligence Programming”, School of Informatics
Get lower result and use it (1) ourlength([ ], 0). ourlength([_|Rest], Size) :- ourlength(Rest, RestSize), % result from below Size is RestSize + 1. % and use it 3 “Introduction to Artificial Intelligence Programming”, School of Informatics
Get lower result and use it (2) factorial(0, 1). factorial(Number, Result) :- NewNumber is Number - 1, factorial(NewNumber, NewResult), % result from below Result is Number * NewResult. % and use it 4 “Introduction to Artificial Intelligence Programming”, School of Informatics
Get lower result and use it (3) reverse( [ ], [ ] ). reverse( [Head|Tail], Answer ) :- reverse( Tail, RevTail ), % result from below append( RevTail, [Head], Answer ). % and use it (Not ideally efficient – processing time is proportional to square of length of original list.) 5 “Introduction to Artificial Intelligence Programming”, School of Informatics
Accumulators • Define an auxiliary predicate with an extra argument . • The extra argument accumulates the result during the computation. • The base case ensures that the accumulated value is put in the correct place. • The main predicate (with original number of arguments) invokes the auxiliary predicate. • The initial invocation of the auxiliary predicate must ensure that the initial value of the accumulator argument is appropriate. 6 “Introduction to Artificial Intelligence Programming”, School of Informatics
Using a numeric accumulator (1) % From C & M - computing length of list: listlen(List, N):- lenacc(List, 0, N). % Use auxiliary procedure, extra argument: lenacc([ ], Acc, Acc). % make final value the result lenacc([_Head|Tail], Acc, N):- Acc1 is Acc +1, % increase accumulator lenacc(Tail, Acc1, N). % count rest 7 “Introduction to Artificial Intelligence Programming”, School of Informatics
Using a numeric accumulator (2) % Counting how many ‘atoms’ in a list, % including inside any nested lists. count(L, R):- countacc(L, 0, R). % initially counter is 0 countacc([ ], Acc, Acc). % make final value the result countacc(X, Acc, W):- % if item is atom, count it atomic(X), W is Acc+1. countacc([Head|Tail], Acc, Res):- % recursively count head and tail, % passing across running total countacc(Head, Acc, Newacc), countacc(Tail, Newacc, Res). 8 “Introduction to Artificial Intelligence Programming”, School of Informatics
Numeric accumulator, delayed % Computing length of list: leng(List, Size):- lengaux(List, 0, Size). lengaux([ ], Acc, Res):- % evaluate built-up expression Res is Acc. lengaux([_|L], Acc, Res):- % recurse with bigger expression % (no evaluation yet) lengaux(L, Acc +1, Res). 9 “Introduction to Artificial Intelligence Programming”, School of Informatics
Trace of delayed evaluation | ?- leng([a,b,c],P). + 1 1 Call: leng([a,b,c],_205) ? + 2 2 Call: lengaux([a,b,c],0,_205) ? + 3 3 Call: lengaux([b,c],0+1,_205) ? + 4 4 Call: lengaux([c],0+1+1,_205) ? + 5 5 Call: lengaux([ ],0+1+1+1,_205) ? 6 6 Call: _205 is 0+1+1+1 ? 6 6 Exit: 3 is 0+1+1+1 ? + 5 5 Exit: lengaux([ ],0+1+1+1,3) ? + 4 4 Exit: lengaux([c],0+1+1,3) ? + 3 3 Exit: lengaux([b,c],0+1,3) ? + 2 2 Exit: lengaux([a,b,c],0,3) ? + 1 1 Exit: leng([a,b,c],3) ? P = 3 ? yes 10 “Introduction to Artificial Intelligence Programming”, School of Informatics
Using a list accumulator (1) A more efficient list-reversal – this stacks elements on to the accumulator. reverse( List, ReversedList ) :- reverse( List, [], ReversedList ). reverse([], List, List). reverse([H|T], SoFar, Reversed) :- reverse(T, [H|SoFar], Reversed). (Processing time is proportional to length of original list.) 11 “Introduction to Artificial Intelligence Programming”, School of Informatics
Using a list accumulator (2) Finding all items which appear in both of two lists. intersect(Set1, Set2, Result):- % Start with empty accumulator intersect(Set1, Set2, [ ], Result). intersect( [ ], _ , V, V). % base case 1 % Make accumulator the result intersect( _ , [ ], V, V). % base case 2 % Make accumulator the result intersect([A|L1], L2, Acc, Res):- % If A in L2, remove, leaving RestL2 takefrom(A, L2, RestL2), % Add A to accumulator, work on RestL2 intersect(L1, RestL2, [A|Acc], Res). intersect([_A|L1], L2, Acc, Res):- % If A not in L2, use same accumulator intersect(L1, L2, Acc, Res). 12 “Introduction to Artificial Intelligence Programming”, School of Informatics
Building on to uninstantiated variable (1) If item X is in the list List , return a list of the other items; otherwise fail. (Assumes X is present at most once). takefrom(X, [X|List], List). takefrom(X, [Y|List], [Y|Newlist]):- % to build up the result, put Y on to % front of yet-to-be-built list takefrom(X, List, Newlist). 13 “Introduction to Artificial Intelligence Programming”, School of Informatics
Building on to uninstantiated variable (2) Finding all items which appear in both of two lists. inboth([ ], _ , [ ]). inboth( _ , [ ], [ ]). inboth([A|L1], L2, [A|Res]):- takefrom(A, L2, RestL2), inboth(L1, RestL2, Res). inboth([ _ |L], L2, Res):- inboth(L, L2, Res). 14 “Introduction to Artificial Intelligence Programming”, School of Informatics
Summary • During recursion, a result value often has to be computed. • This can be done by a simple recursive call followed by some further computation. • Alternatively, an auxiliary predicate with an accumulator argument can be used. • A very common form is to recurse on an uninstantiated structure. 15 “Introduction to Artificial Intelligence Programming”, School of Informatics
Recommend
More recommend