The definition of app/3 was:
% 1 terminating condition
app([], List, List).
% 2 recursive
app([Hd|Tl1], List2, [Hd|Tl3]) :-
app(Tl1, List2, Tl3).
We could use this to find:
| ?- app([a,b,c], [1,2,3], List).
List=[a,b,c,1,2,3] ? ;
no
This is the use we would expect of such a procedure: we're asking
"what does [a,b,c] and [1,2,3] make when appended?".
We can ask an alternative question: what pairs of lists, when appended,
make [a,b,c,1,2,3].
| ?- app(List1, List2, [a,b,c,1,2,3]).
List1 = []
List2 = [a,b,c,1,2,3] ? ;
List1 = [a]
List2 = [b,c,1,2,3] ? ;
List1 = [a,b]
List2 = [c,1,2,3] ? ;
List1 = [a,b,c]
List2 = [1,2,3] ? ;
List1 = [a,b,c,1]
List2 = [2,3] ? ;
List1 = [a,b,c,1,2]
List2 = [3] ? ;
List1 = [a,b,c,1,2,3]
List2 = [] ? ;
no
We can see that there are seven possible pairs that make up the original
list.
One way of looking at what we have done is that we have used this
procedure normally (ie we have found what the appending of two lists
will give), and "back-to-front" (ie by finding the question for
which know the answer). This way of using procedures in more than
one way is one of logic programming's strengths. Given enough imagination
the part of the programmer, it is possible to create some very elegant
and simple solutions to problems. However, as will be seen later
in the course, it is quite easy to get caught out by inadvertently
finding infinite branches in the search tree: ie situations where
Prolog will recurse forever without finding a solution.
|