Lecture 1
Lecture 2
Lecture 3
Lecture 4
Lecture 5


Compare the following two definitions of the list-length predicate. Do a trace to see how the result is computed.

list_length1([_|Tail],Length) :- 
             Length is TailLength + 1.
Download knowledge base.
list_length2(List,Length) :- list_length2(List,0,Length).

list_length2([_|Tail],Accumulator,Length) :-
             NewAcc is Accumulator + 1, 
Download knowledge base.

The main difference that you can observe when doing a trace is that list_length1 computes the result when coming out of the recursion, while list_length2 computes the result while going into the recursion. At the time where the bottom of the recursion (the empty list) has been reached, the length of the list has already been established. To be able to do this, list_length2 uses an accumulator, i.e., an argument for storing intermediate results. In the beginning, the accumulator is instantiated with 0. In each recursive call, the accumulator argument is increased by one (to indicate that one more list element has been processed). By the time the empty list is reached, the accumulator argument contains a number corresponding to the length of the list.

The accumulator adds an extra argument to the predicate which has to be instantiated when the predicate is first called. We use a wrapper predicate to do this automatically:

list_length2(List,Length) :- list_length2(List,0,Length).

Define an accumulator version of the predicate max/2 that you had to define in this exercise.

Define a predicate mirror(+InList,?OutList) which takes a list as argument and turns it around. For example, the query mirror([a,b,c,d],L) should yield the answer L = [d,c,b,a]. Use an accumulator and don't use append, such that the result is ready when the empty list is reached.

Define an accumulator version of the flattening predicate defined in this exercise.

Back to the practical session of day 3.