Session 6:
Accumulating parameters +
graphs
sumlist([], 0).
sumlist([H|T], Sum)
:-sumlist(T, TmpSum), Sum is TmpSum + H.
?- sumlist([5,4,9,8], S).
sumlist([], 0). sumlist([H|T], Sum) :-sumlist(T, TmpSum), Sum is TmpSum + H. ?- sumlist([5,4,9,8], S). ?- sumlist([4,9,8],TmpS1), S is TmpS1 + 5. ?- sumlist([9,8],TmpS2), TmpS1 is TmpS2 + 4, S is TmpS1 + 5. ?- sumlist([8],TmpS3), TmpS2 is TmpS3 + 9, TmpS1 is TmpS2 + 4, S is TmpS1 + 5. ?- sumlist([],TmpS4), TmpS3 is TmpS4 + 8, TmpS2 is TmpS3 + 9, TmpS1 is TmpS2 + 4, S is TmpS1 + 5. ?- TmpS3 is 0 + 8, TmpS2 is TmpS3 + 9, TmpS1 is TmpS2 + 4, S is TmpS1 + 5. ?- TmpS2 is 8 + 9, TmpS1 is TmpS2 + 4, S is 5 + TmpS1. ?- TmpS1 is 17 + 4, S is 5 + TmpS1. ?- S is 5 + 21. 1 goal 2 goals 3 goals 4 goals 5 goals 4 goals 3 goals 2 goals 1 goal
Memory usage!
sumlist([], 0). sumlist([H|T], Sum) :-sumlist(T, TmpSum), Sum is TmpSum + H. sumlist(List, Sum) :-sumlist_acc(List, Sum, 0).
% sumlist_acc(List, OutputSum, Accumulator)
sumlist_acc([], Sum, Sum).
sumlist_acc([H|T], Sum, AccSum) :-NewAccSum is AccSum + H,
sumlist_acc(T, Sum, NewAccSum).
Make it tail-recursive by introducing
accumulator:
sumlist(List, Sum)
:-sumlist_acc(List, Sum, 0). sumlist_acc([], Sum, Sum).
sumlist_acc([H|T], Sum, AccSum) :-NewAccSum is AccSum + H,
sumlist_acc(T, Sum, NewAccSum). ?- sumlist([5,4,9,8], S). ?- sumlist_acc([5,4,9,8], S, 0). ?- NewAccS1 is 0 + 5, sumlist_acc([4,9,8], S, NewAccS1).
1 goal
2 goals
?- sumlist_acc([4,9,8],S, 5). ?- NewAccS2 is 5 + 4, sumlist_acc([9,8], S, NewAccS2). ?- sumlist_acc([9,8], S, 9). ?- NewAccS3 is 9 + 9, sumlist_acc([8], S, NewAccS3). ?- sumlist_acc([8], S, 18). ?- NewAccS4 is 18 + 8, sumlist_acc([], S, NewAccS4).
?- sumlist_acc([], S, 26). 1 goal 2 goals 1 goal 1 goal 1 goal 2 goals 2 goals
Reverse without accumulator:
reverse([], []).
reverse([Head|Tail], Reversed):-reverse(Tail, TailReversed),
append(TailReversed, [Head], Reversed).
Reverse with accumulator:
reverse(List,
Reversed):-reverse_acc(List, Reversed, []). reverse_acc([], Result, Result).
reverse_acc([Head|Tail], Result,
Acc):-reverse_acc(Tail, Result, [Head|Acc]).
Possible exercise: draw a call tree for
?- reverse([1, 2, 3], Reversed).for both versions
quadratic time-complexity: O(N2)
list_length_2(List, Length)
:-list_length_acc(List, Length, 0).
list_length_acc([], Length, Length).
list_length_acc([ _Head|Tail], Length,
Acc):-Acc1 is Acc +1,
list_length_acc(Tail, Length, Acc1).
Draw a call tree for
?- list_length([a, b, c], Length)
(without accumulator)
and for (with and without accumulator)
?- list_length_2([a, b, c], Length)
(with accumulator)
L = [5, 3, 7, 8, 1, 4, 7, 6] Tail = [3, 7, 8, 1, 4, 7, 6] Small = [3, 1, 4] Big = [7, 8, 7, 6] SortedSmall = [1, 3, 4] SortedBig = [6, 7, 7, 8] Sorted = [1, 3, 4, 5, 6, 7, 7, 8] Delete X, X = 5 Quicksort of Big Quicksort of Small Quicksort of L Split All <= X All > X Add X concatenate
1.2 Quicksort
quicksort_2(List, Sorted)
:-quicksort_acc(List, [], Sorted).
quicksort_acc([], Sorted, Sorted).
quicksort_acc([X|Tail], Acc, Sorted)
:-split(X, Tail, Small, Big),
quicksort_acc(Big, Acc, NewAcc),
quicksort_acc(Small, [X|NewAcc], Sorted).
Intuition: in
quicksort_acc(List, Acc, Sorted) :
• Acc is a sorted list of elements larger than or equal to the
elements in List.
• Sorted is a list:
• Starting with the sorted elements of List
• Followed by the elements from Acc
1.3 Computing Fibonacci numbers
From exercise session 2:
fib(1,1).
fib(2,1).
fib(N, F)
:-N > 2,
N1 is N-1,
fib(N1, F1),
N2 is N-2,
fib(N2, F2),
F is F1 + F2.
fibo(N, Fib)
:-fib(1 ,N, 0, 1, Fib).
fib(N, N, _, Result, Result).
fib(Count, N, PreviousFib, CurrentFib,
Result):-Count < N,
NextCount is Count + 1,
NextFib is CurrentFib + PreviousFib,
fib(NextCount, N, CurrentFib, NextFib, Result).
1st argument: which step we are in
2nd argument: which fibonacci number we eventually want to compute 3th argument: the fibonacci number for the previous step
4th argument: the fibonacci number for the current step
5th argument: where we will return the solution when the recursion has finished.
get_doubles(List, Doubles)
:-get_doubles_acc(List, Doubles, [], []).
get_doubles_acc([], Doubles, _, Doubles).
get_doubles_acc([El|T], Result, Singles,
Doubles):-% we have seen the element El twice (or more) before member(El, Doubles), !,
get_doubles_acc(T, Result, Singles, Doubles). get_doubles_acc([El|T], Result, Singles,
Doubles):-% we have seen the element El once before
member(El, Singles), remove(El, Singles, NewSingles), !, get_doubles_acc(T, Result, NewSingles, [El | Doubles]). get_doubles_acc([El|T] ,Result, Singles,
Doubles):-% we have not seen the element El before
get_doubles_acc(T, Result, [El | Singles], Doubles).
arc(From, To, Graph) :-member(From/To, Graph). connected(X ,X, _). connected(X, Y, Graph) :-arc(Z, Y, Graph), connected(X, Z, Graph).
find_path(X, Y, Path, Graph)
:-find_path_acc(X, Y, Path, [Y], Graph). find_path_acc(X, X, Path, Path, _).
find_path_acc(X, Y, Path, Acc, G) :-arc(Z, Y, G),
find_path_acc(X, Z, Path, [Z|Acc], G).
find_path_2(X, Y, Path, Graph)
:-find_path_acc_2(X, Y, Path, [Y], Graph). find_path_acc_2(X ,X, Path, Path, _).
find_path_acc_2(X, Y, Path, Acc, G) :-arc(Z, Y, G),
not(member(Z, Acc)), % <--- only difference
find_path_acc_2(X, Z, Path, [Z| Acc], G). connected_2(X, Y,
Graph):-find_path_2(X, Y, _, Graph).
arc(From,To,Graph)
:-member(From/To,Graph). arc(From,To,Graph)
:-member(To/From,Graph).