This is an algorithm to append together two lists:
Domains
list= integer*
Predicates
nondeterm append(list, list, list)
Clauses
append([], List, List) :- !.
append([H|L1], List2, [H|L3]) :- append(L1, List2, L3).
Goal
append([9,2,3,4], [-10,-5,6,7,8], Ot).
The result is a list [9,2,3,4,-10,-5,6,7,8]
, and it's saved in "Ot
".
My question is, how does this work?
What I understand is that in every recursive call, in the first list, you get only the tail as a list ( thus reducing its size by 1
until it's []
), the second argument "List2
" does not change at all, and the 3rd argument ... at first it's []
, and after each recursive call you get its tail, but since it's []
, it stays []
.
So how come, suddenly, in 3rd argument ("Ot
") we have the appended list ?
Can someone explain this algorithm step by step ?
Let's translate from Prolog into English. We have two rules:
The result of appending any
List
to[]
is thatList
.The result of appending any
List
to a list whose first element isH
and remainder isL1
is equal to a list whose first element is alsoH
whose remainder is the result of appendingList
toL1
.So, we want to append
[-10,-5,6,7,8]
to[9,2,3,4]
. The list being appended to isn't empty, so we can skip that rule. By the second rule, the result has9
as the first element, followed by the result of appending[-10,-5,6,7,8]
to[2,3,4]
.So, we want to append
[-10,-5,6,7,8]
to[2,3,4]
. The list being appended to isn't empty, so we can skip that rule. By the second rule, the result has2
as the first element, followed by the result of appending[-10,-5,6,7,8]
to[3,4]
.So, we want to append
[-10,-5,6,7,8]
to[3,4]
. The list being appended to isn't empty, so we can skip that rule. By the second rule, the result has3
as the first element, followed by the result of appending[-10,-5,6,7,8]
to[4]
.So, we want to append
[-10,-5,6,7,8]
to[4]
. The list being appended to isn't empty, so we can skip that rule. By the second rule, the result has9
as the first element, followed by the result of appending[-10,-5,6,7,8]
to[]
.So, we want to append
[-10,-5,6,7,8]
to[]
. The list being appended to is empty, so by the first rule, the result is[-10,-5,6,7,8]
.Since the result of appending
[-10,-5,6,7,8]
to[]
is[-10,-5,6,7,8]
, the result of appending[-10,-5,6,7,8]
to[4]
is[4,-10,-5,6,7,8]
.Since the result of appending
[-10,-5,6,7,8]
to[4]
is[4,-10,-5,6,7,8]
, the result of appending[-10,-5,6,7,8]
to[3,4]
is[3,4,-10,-5,6,7,8]
.Since the result of appending
[-10,-5,6,7,8]
to[3,4]
is[3,4,-10,-5,6,7,8]
, the result of appending[-10,-5,6,7,8]
to[2,3,4]
is[2,3,4,-10,-5,6,7,8]
.Since the result of appending
[-10,-5,6,7,8]
to[2,3,4]
is[2,3,4,-10,-5,6,7,8]
, the result of appending[-10,-5,6,7,8]
to[9,2,3,4]
is[9,2,3,4,-10,-5,6,7,8]
.First, let's translate the clauses into something more understandable:
can be written
and
can be written
I hope this will already be clearer for you.
Then, step by step, the number indicates the clause used each time, and the resulting call is shown:
At this step all the values we're interested in are already defined. Notice how the head of the result is set before its tail is filled up by a subsequent (tail recursive) call to
append
, building the resulting list in the characteristic for Prolog top-down fashion (also known as "tail recursion modulo cons").Let's follow the definitions to see what
Ot
is, at the final step:I hope you'll get something out of it.