Lab 4
Lab 4
Lists
1. Lists
A list is a finite sequence of elements. Here are some examples of lists in Prolog:
● [mia, vincent, jules, yolanda]
● [mia, robber(honey_bunny), X, 2, mia]
● []
● [mia, [vincent, jules], [butch, girlfriend(butch)]]
● [[], dead(zed), [2, [b, chopper]], [], Z, [2, [b,
chopper]]]
1
is the list [vincent,jules], and the third element is
[butch,girlfriend(butch)]. In short, lists are examples of recursive
data structures: lists can be made out of lists. The length of the fourth list is
three. The elements of the list are the things between the outermost
square brackets separated by commas. So this list contains three
elements.
5. The last example mixes all these ideas together. We have here a list which
contains the empty list (in fact, it contains it twice), the complex term
dead(zed), two copies of the list [2, [b, chopper]], and the variable
Z. Note that the third (and the last) elements are lists which themselves
contain lists (namely [b, chopper]).
Any non-empty list can be thought of as consisting of two parts: the head and the
tail. The head is simply the first item in the list; the tail is everything else. Or
more precisely, the tail is the list that remains when we take the first element
away, i.e. the tail of a list is always a list again.
For example, the head of [mia, vincent, jules, yolanda] is mia and
the tail is [vincent, jules, yolanda].
For the list [dead(zed)], the head is the first element of the list, which is
dead(zed), and the tail is the list that remains if we take the head away, which,
in this case, is the empty list [].
Note that only non-empty lists have heads and tails. That is, the empty list
contains no internal structure. For Prolog, the empty list [] is a special, particularly
simple, list.
Prolog has a special inbuilt operator | which can be used to decompose a list
into its head and tail. It is a key tool for writing Prolog list manipulation
programs.
2
The most obvious use of | is to extract information from lists. We do this by using
| together with matching. For example, to get hold of the head and tail of
[mia,vincent, jules,yolanda] we can pose the following query:
?- [Head| Tail] = [mia, vincent, jules, yolanda].
Head = mia
Tail = [vincent,jules,yolanda]
yes
That is, the head of the list has become bound to Head and the tail of the list has
become bound to Tail.
Note that there is nothing special about Head and Tail, they are simply
variables. We could just as well have posed the query:
?- [X|Y] = [mia, vincent, jules, yolanda].
X = mia
Y = [vincent,jules,yolanda]
yes
As mentioned above, only non-empty lists have heads and tails. If we try to use |
to pull [] apart, Prolog will fail:
?- [X|Y] = [].
no
That is, Prolog treats [] as a special list.
But we can can do a lot with |; it really is a very flexible tool. For example,
suppose we wanted to know what the first two elements of the list were, and also
the remainder of the list after the second element. Then we’d pose the following
query:
?- [X,Y | W] = [[], dead(zed), [2, [b, chopper]], [], Z].
X = []
3
Y = dead(zed)
W = [[2,[b,chopper]],[],_8327]
Z = _8327
yes
4
Let’s look at one last example. The third element of our working example is a list.
Suppose we wanted to extract the tail of this internal list, and that we are not
interested in any other information.The query would be as follows:
?- [_,_,[_|X]|_] =
[[], dead(zed), [2, [b, chopper]], [], Z, [2,
[b, chopper]]].
X = [[b,chopper]]
Z = _10087
yes
2. Member
One of the most basic things we would like to know is whether something is an
element of a list or not. So let’s write a program that, when given as inputs an
arbitrary object X and a list L, tells us whether or not X belongs
to L.
The program that does this is usually called member, and it is the simplest
example of a Prolog program that exploits the recursive structure of lists. Here it
is:
member(X,[X|T]).
member(X,[H|T]) :- member(X,T).
5
Now consider the following query:
?- member(vincent,[yolanda,trudy,vincent,jules]).
Now the first rule fails so Prolog goes to the second clause, the recursive rule.
This gives Prolog a new goal: it now has to see if
member(vincent,[trudy,vincent,jules]).
Again the first clause won’t help, so Prolog goes to the recursive rule. This gives
it a new goal, member(vincent,[vincent,jules]).
This time, the first clause does help, and the query succeeds.
What about when X is not a member of the list? Use trace mode to find out.
Let’s suppose we need a predicate a2b/2 that takes two lists as arguments, and
succeeds if the first argument is a list of as, and the second argument is a list of
bs of exactly the same length. For example, if we pose the following query
a2b([a,a,a,a],[b,b,b,b]).
we want Prolog to say ‘yes’. On the other hand, if we pose the
a2b([a,a,a,a],[b,b,b]).
or the query
6
a2b([a,c,a,a],[b,b,5,4]).
we want Prolog to say ‘no’.
Try posing the following queries on the predicate and understand their working
using trace mode.
a2b([a,a,a],[b,b,b]).
a2b([a,a,a,a],[b,b,b]).
a2b([a,c,a,a],[b,b,5,4]).
a2b([a,a,a,a],X).
a2b(X,Y).
4. Exercises
7
k. [] = [_|[]].
8
X = [1,1,2,2,1,1,1,1]