You are on page 1of 32

University of Monastir

Declarative Programming (Master Level)


List Manipulation

Brahim Hnich

Department of Computer Science


Fall 2016–1017

Tuesday, october 11th, 2016

. . . .... .... .... . . . . .


List Manipulation

Lists in Prolog

One of the most useful data structures in Prolog are lists. The
objective of this lecture is to show you how lists are represented in
Prolog and to introduce you to the basic principles of working with
lists.

Example Prolog lists:


[elephant, horse, donkey, dog].

[a, X, [], f(X,y), 47, [a,b,c], bigger(cow,dog)]

Lists are enclosed in square brackets. Their elements could be any


Prolog terms (including other lists).

The empty list is [].


. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
2
List Manipulation

Internal Representation

Internally, the list


[a, b, c]

corresponds to the term


.(a, .(b, .(c, [])))

That means, this is just a new notation. Internally, lists are just
compound terms with the functor . (dot) and the special atom [] as
an argument on the innermost level.
We can verify this also in Prolog:
?- X = .(a, .(b, .(c, []))).
X = [a, b, c]
Yes
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
3
List Manipulation

The Bar Notation

If a bar | is put just before the last term in a list, it means that this
last term denotes a sub-list.

Inserting the elements before the bar at the beginning of the sub-list
yields the entire list.

For example, [a, b, c, d] is the same as [a, b | [c, d]].

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
4
List Manipulation

Examples

Extract the second element from a given list:


?- [a, b, c, d, e] = [ , X | ].

X = b

Yes

Make sure the first element is a 1 and get the sub-list after the
second element:
?- MyList = [1, 2, 3, 4, 5], MyList = [1, | Rest].

MyList = [1, 2, 3, 4, 5]

Rest = [3, 4, 5]

Yes
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
5
List Manipulation

Head and Tail

The first element of a list is called its head.


The rest of the list is called its tail.
The empty list doesnt have a head.
A special case of the bar notation with exactly one element before
the bar is called the head/tail-pattern. It can be used to extract head
and/or tail from a list.
Example:
?- [elephant, horse, tiger, dog] = [Head | Tail].
Head = elephant
Tail = [horse, tiger, dog]
Yes
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
6
List Manipulation

Head and Tail

Another example:
?- [elephant] = [X | Y].

X = elephant

Y = []

Yes

Note: The tail of a list is always a list itself. The head of a list is an
element of that list. The head could also be a list itself.

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
7
List Manipulation

Appending Lists

We want to write a predicate concat lists/3 to concatenate


(append) two given lists.

It should work like this:


?- concat lists([1, 2, 3, 4], [dog, cow, tiger], L).

L = [1, 2, 3, 4, dog, cow, tiger]

Yes

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
8
List Manipulation

Solution

The predicate concat lists/3 is implemented recursively.

The base case is when one of the lists is empty.

In every recursion step we take off the head and use the same
predicate again, with the (shorter) tail, until we reach the base case.
concat lists([], List, List).

concat lists([Elem|List1], List2, [Elem|List3]) :-

concat lists(List1, List2, List3).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
9
List Manipulation

Do More

Amongst other things, concat lists/3 can also be used for


decomposing lists:
?- concat lists(Begin, End, [1, 2, 3]).
Begin = []
End = [1, 2, 3] ;
Begin = [1]
End = [2, 3] ;
Begin = [1, 2]
End = [3] ;
Begin = [1, 2, 3]
End = [] ;
No
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
10
List Manipulation

Built-in Predicates for List Manipulation

append/3: Append two lists (same as our concat lists/3).


?- append([1, 2, 3], List, [1, 2, 3, 4, 5]).

List = [4, 5]

Yes

length/2: Get the length of a list.


?- length([tiger, donkey, cow, tiger], N).

N = 4

Yes

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
11
List Manipulation

Membership

member/2: Test for membership.


?- member(tiger, [dog, tiger, elephant, horse]).

Yes

Backtracking into member/2:


?- member(X, [dog, tiger, elephant]).

X = dog ;

X = tiger ;

X = elephant ;

No

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
12
List Manipulation

Membership

member(X,[X| ]).

member(X,[ |T]):- member(X,T).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
13
List Manipulation

Summary: List Manipulation

List notation:
normal: [Elem1, Elem2, Elem3] (empty list: [])

internal: .(Elem1, .(Elem2, .(Elem3, [])))

bar notation: [Elem1, Elem2 | Rest]

head/tail-pattern: [Head | Tail]

Many predicates can be implemented recursively, exploiting the


head/tail-pattern.

Built-in predicates: append/3, member/2, length/2, . . .

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
14
Applications

Example*
Displaying the Elements of a List

Consider the following program:


show(List) :-

member(Element, List),

write(Element),

nl,

fail.

Note: fail is a built-in predicate that always fails.


What happens when you submit a query like the following one?
?- show([elephant, horse, donkey, dog]).
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
15
Applications

Example*
Displaying the Elements of a List

?- show([elephant, horse, donkey, dog]).


elephant
horse
donkey
dog
No

The fail at the end of the rule causes Prolog to backtrack.


The subgoal member(Element, List) is the only choicepoint.
In every backtracking-cycle a new element of List is matched with
the variable Element.
Eventually, the query fails (No).
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
16
Applications

Example*
Finding the last element in a list

last(X,L) if X is the last element of list L.

last(X,[X]).

last(X,[ |T]) :-

last(X,T).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
17
Applications

Example*
Finding the last but one element in a list

lastbutone(X,L) if X is the last but one element of list L.

lastbutone(X,[X, ]).

lastbutone(X,[ ,Y|T]) :-

lastbutone(X,[Y|T]).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
18
Applications

Example*
Duplicate each element of a list

dupli(L1,L2) if list L2 is obtained from list L1 by duplicating all


elements.

dupli([],[]).

dupli([X|Xs],[X,X|Ys]) :-

dupli(Xs,Ys).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
19
Applications

Example*
Prefix

prefix(P,L) if list P is a prefix of list L.


?-prefix(P,[a,b,c,d]).

P = [] ;

P = [a] ;

P = [a,b] ;

P = [a,b,c] ;

P= [a,b,c,d] ;

No
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
20
Applications

Example*
Prefix

prefix(P,L) if list P is a prefix of list L.

prefix(P,L) :- append(P, ,L).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
21
Applications

Example*
Suffix

suffix(S,L) if list S is a suffix of list L.


?-suffix(S,[a,b,c,d]).

S = [] ;

S = [d] ;

S = [c,d] ;

S = [b,c,d] ;

S = [a,b,c,d] ;

No
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
22
Applications

Example*
Suffix

suffix(S,L) if list S is a suffix of list L.

suffix(S,L) :- append( ,S,L).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
23
Applications

Example*
Finding Sublists

sublist(I,L) if list I is a sub-list of list L.


?-sublist(I,[a,b,c,d]).
I = [] ;
I = [a] ;
I = [b] ;
I = [c] ;
i = [d] ;
I = [a, b] ;
I = [b, c] ;
I = [c, d] ;
I = [a, b, c] ;
I = [b, c, d] ;
I = [a,b, c, d] ;
No
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
24
Applications

Example*
Finding Sublists

sublist(I,L) if list I is a sub-list of list L.

sublist(I,L) :- suffix(S,L), prefix(I,S).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
25
Applications

Example**
Flatten a nested list structure

my flatten(L1,L2) if the list L2 is obtained from the list L1 by


flattening; i.e. if an element of L1 is a list then it is replaced by its
elements, recursively.

my flatten(X,[X]) :- \+ is list(X).
my flatten([],[]).
my flatten([X|Xs],Zs) :-
my flatten(X,Y),
my flatten(Xs,Ys),
append(Y,Ys,Zs).
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
26
Applications

Example*
Reversing a list

myreverse(L,R) if list R is the reverse of list L.

?-myreverse([a,[b,c],d],R).

R = [d,[b,c],a]

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
27
Applications

Example*
Reversing a List

myreverse(L,R) if list R is the reverse of list L.

myreverse([],[]).

myreverse([H|T],R) :-

myreverse(T,RT),

append(RT,[H],R).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
28
Applications

Example*
Find out whether a list is a palindrome

palindrome(L) if list L is a palindrome.

A palindrome can be read forward or backward; e.g. [x,a,m,a,x].

palindrome(L) :-

reverse(L,L).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
29
Applications

Example**
Reversing a list w/o using append/3

myreverse1(L,R) if list R is the reverse of list L.

myreverse1(L,R) :- rev(L, [], R).

rev([], R, R).

rev([H|T], L, R) :-

rev(T, [H|L], R).

. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
30
Applications

Example**
Eliminate consecutive duplicates of list elements

compress(L1,L2) if the list L2 is obtained from the list L1 by


compressing repeated occurrences of elements into a single copy of
the element.

compress([],[]).
compress([X],[X]).
compress([X,X|Xs],Zs) :-
compress([X|Xs],Zs).
compress([X,Y|Ys],[X|Zs]) :-
X \= Y, compress([Y|Ys],Zs).
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
31
Applications

Example**
Pack consecutive duplicates of list elements into sublists

pack(L1,L2) if the list L2 is obtained from the list L1 by packing


repeated occurrences of elements into separate sublists.

pack([],[]).
pack([X|Xs],[Z|Zs]) :- transfer(X,Xs,Ys,Z), pack(Ys,Zs).

transfer(X,Xs,Ys,Z) if Ys is the list that remains from the list Xs


when all leading copies of X are removed and transferred to Z
transfer(X,[],[],[X]).
transfer(X,[Y|Ys],[Y|Ys],[X]) :-
X \= Y.
transfer(X,[X|Xs],Ys,[X|Zs]) :-
transfer(X,Xs,Ys,Zs).
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
32

You might also like